I'm trying to write a generic function to serialize to string a std::vector<cv::Point_<T>> and I want this to work for both cv::Point2i and cv::Point2f (both are typedefs of cv::Point_<T> with a specific T).
The function looks like this:
template<typename T>
int SVIniFile::write(const std::string& section,
const std::string& key,
std::vector<cv::Point_<T>>& points)
{
std::ostringstream os;
if (points.empty())
{
return SUCCESS;
}
for (size_t j = 0; j < points.size(); j++)
{
os << points[j].x << " " << points[j].y;
if (j < points.size() - 1)
{
os << " ";
}
}
write(section, key, os.str()); // do the writing of os.str() in the right `section` at `key`
return SUCCESS; // function that writes a string into an ini file
}
Trying to compile this throws an "Unrecognizable template declaration/definition" error. Investigating on the error (full compiler output is below), I found this question, which however doesn't seem related to my case, and this question, the answer of which I don't understand.
I'm very new to template programming and I suspect the error is caused by the fact that I'm using as template parameter the type that is itself a template parameter of one of the parameters. Could anyone point me in the right direction and possibly expand a bit on why the compiler can't build this?
This is what the compiler produces as error output in every file where my header is included:
1>svinifile.h(640): error C4430: missing type specifier - int assumed.
Note: C++ does not support default-int 1>svinifile.h(640): error
C2988: unrecognizable template declaration/definition
1>svinifile.h(640): error C2143: syntax error: missing ',' before '&'
line 640 is the one right after the template<typename T> in the function definition I show above.
Just to be explicit, cv::Point_<T> i OpenCV's 2D point type defined in types.hpp as:
namespace cv
{
// ...
template<typename _Tp> class Point_
{
public:
typedef _Tp value_type;
//! default constructor
Point_();
Point_(_Tp _x, _Tp _y);
Point_(const Point_& pt);
Point_(Point_&& pt) CV_NOEXCEPT;
Point_(const Size_<_Tp>& sz);
Point_(const Vec<_Tp, 2>& v);
Point_& operator = (const Point_& pt);
Point_& operator = (Point_&& pt) CV_NOEXCEPT;
//! conversion to another data type
template<typename _Tp2> operator Point_<_Tp2>() const;
//! conversion to the old-style C structures
operator Vec<_Tp, 2>() const;
//! dot product
_Tp dot(const Point_& pt) const;
//! dot product computed in double-precision arithmetics
double ddot(const Point_& pt) const;
//! cross-product
double cross(const Point_& pt) const;
//! checks whether the point is inside the specified rectangle
bool inside(const Rect_<_Tp>& r) const;
_Tp x; //!< x coordinate of the point
_Tp y; //!< y coordinate of the point
};
typedef Point_<int> Point2i;
typedef Point_<int64> Point2l;
typedef Point_<float> Point2f;
typedef Point_<double> Point2d;
typedef Point2i Point;
}
Since there's nothing wrong with the code shown, the problem must be with some code you have not shown. It's probably something very simple, like a missing or out-of-order #include.
You should try to create a Minimal, Complete, and Verifiable example. You'll likely find the problem while doing it.
For example, this compiles just fine on VS 2017:
#include <vector>
namespace cv {
template<typename _Tp> class Point_ {};
typedef Point_<int> Point2i;
}
class SVIniFile {
public:
template<typename T>
int write(
const std::string& section,
const std::string& key,
std::vector<cv::Point_<T>>& points);
};
template<typename T>
int SVIniFile::write(
const std::string& section,
const std::string& key,
std::vector<cv::Point_<T>>& points) {
return 0;
}
int main() {
SVIniFile svIniFile;
std::vector<cv::Point2i> points;
svIniFile.write("abc", "def", points);
return 0;
}
Related
I want my custom complex type to be able to interact with std::complex, but in certain cases, the compiler do not convert my type to std::complex.
Here is a minimal working example:
#include <complex>
#include <iostream>
template <typename Expr>
class CpxScalarExpression
{
public:
inline std::complex< double > eval() const { return static_cast<Expr const&>(*this).eval(); }
inline operator std::complex< double >() const { return static_cast<Expr const&>(*this).eval(); }
};
class CpxScalar : public CpxScalarExpression<CpxScalar>
{
public:
CpxScalar() : m_value(0) {}
CpxScalar(const double value) : m_value(value) {}
CpxScalar(const double real_value, const double imag_value) : m_value(real_value, imag_value) {}
CpxScalar(const std::complex< double > value) : m_value(value) {}
template<typename Expr>
CpxScalar(const CpxScalarExpression< Expr >& expr) : m_value(expr.eval()) {}
public:
inline std::complex< double > eval() const { return m_value; }
private:
std::complex< double > m_value;
};
int main()
{
CpxScalar a(10,-5);
//std::complex< double >* b = reinterpret_cast< std::complex< double >* >(&a);
std::complex< double > b = a;
b += a;
//std::cout << b->real() << " " << b->imag();
std::cout << b.real() << " " << b.imag();
}
The compiler fails at deducing which operator+= to call and returns the following error
est.cpp:50:4: error: no match for ‘operator+=’ (operand types are ‘std::complex<double>’ and ‘CpxScalar’)
50 | b += a;
| ~~^~~~
In file included from test.cpp:1:
/usr/include/c++/9/complex:1287:7: note: candidate: ‘std::complex<double>& std::complex<double>::operator+=(double)’
1287 | operator+=(double __d)
| ^~~~~~~~
/usr/include/c++/9/complex:1287:25: note: no known conversion for argument 1 from ‘CpxScalar’ to ‘double’
1287 | operator+=(double __d)
| ~~~~~~~^~~
/usr/include/c++/9/complex:1329:9: note: candidate: ‘template<class _Tp> std::complex<double>& std::complex<double>::operator+=(const std::complex<_Tp>&)’
1329 | operator+=(const complex<_Tp>& __z)
| ^~~~~~~~
/usr/include/c++/9/complex:1329:9: note: template argument deduction/substitution failed:
test.cpp:50:7: note: ‘CpxScalar’ is not derived from ‘const std::complex<_Tp>’
50 | b += a;
| ^
Is there a way to overcome this issue ?
Providing your own overload for the operator is the way to go.
However, there's a few things to keep in mind:
Since you already have a cast available, all you have to do is to use it and let the regular operator take it from there.
Since the type that is meant to "pose" as std::complex is CpxScalarExpression<Expr>, then that should be the one the overload operates on.
std::complex's operator+=() normally allows you to add together complex values of different types, so we should maintain that. Meaning the operator should be templated on the incoming std::complex's components type.
We need to make sure to return exactly whatever std::complex's operator+= wants to return. Using decltype(auto) as the return type of the overload provides you with just that.
Putting all of that together, we land at:
template<typename T, typename Expr>
constexpr decltype(auto) operator+=(
std::complex<T>& lhs,
const CpxScalarExpression<Expr>& rhs) {
return lhs += std::complex<double>(rhs);
}
Dropping that into the code you posted makes it work just as expected, and should give you feature parity with std::complex's operator+=().
A custom operator for += works with your example:
[[maybe_unused]] constexpr static inline std::complex<double> operator+=(
const std::complex<double>& lhs,
const CpxScalar& rhs) noexcept {
return lhs + rhs.eval();
}
The following code compiles perfectly if:
I don't include <iostream> or
I name operator== as alp::operator==.
I suppose there is a problem with <iostream> and operator==, but I don't know what.
I compile the code with gcc 7.3.0, clang++-6.0 and goldbolt. Always the same error.
The problem is that the compiler is trying to cast the parameters of operator== to const_iterator, but why? (I suppose the compiler doesn't see my version of operator==, and looks for other versions).
#include <vector>
#include <iostream> // comment and compile
namespace alp{
template <typename It_base>
struct Iterator {
using const_iterator = Iterator<typename It_base::const_iterator>;
operator const_iterator() { return const_iterator{}; }
};
template <typename It_base>
bool operator==(const Iterator<It_base>& x, const Iterator<It_base>& y)
{ return true;}
}// namespace
struct Func{
int& operator()(int& p) const {return p;}
};
template <typename It, typename View>
struct View_iterator_base{
using return_type = decltype(View{}(*It{}));
using const_iterator =
View_iterator_base<std::vector<int>::const_iterator, Func>;
};
using view_it =
alp::Iterator<View_iterator_base<std::vector<int>::iterator, Func>>;
int main()
{
view_it p{};
view_it z{};
bool x = operator==(z, p); // only compiles if you remove <iostream>
bool y = alp::operator==(z,p); // always compile
}
Error message:
yy.cpp: In instantiation of ‘struct View_iterator_base<__gnu_cxx::__normal_iterator<const int*, std::vector<int> >, Func>’:
yy.cpp:9:73: required from ‘struct alp::Iterator<View_iterator_base<__gnu_cxx::__normal_iterator<const int*, std::vector<int> >, Func> >’
yy.cpp:44:29: required from here
yy.cpp:28:42: error: no match for call to ‘(Func) (const int&)’
using return_type = decltype(View{}(*It{}));
~~~~~~^~~~~~~
yy.cpp:22:10: note: candidate: int& Func::operator()(int&) const <near match>
int& operator()(int& p) const {return p;}
^~~~~~~~
yy.cpp:22:10: note: conversion of argument 1 would be ill-formed:
yy.cpp:28:42: error: binding reference of type ‘int&’ to ‘const int’ discards qualifiers
using return_type = decltype(View{}(*It{}));
~~~~~~^~~~~~~
I've made a more minimal test case here: https://godbolt.org/z/QQonMG .
The relevant details are:
A using type alias does not instantiate a template. So for example:
template<bool b>
struct fail_if_true {
static_assert(!b, "template parameter must be false");
};
using fail_if_used = fail_if_true<true>;
will not cause a compile time error (if fail_if_used isn't used)
ADL also inspects template parameter classes. In this case, std::vector<int>::iterator is __gnu_cxx::__normal_iterator<const int*, std::vector<int> >, Func>, which has a std::vector<int> in it's template. So, operator== will check in the global namespace (always), alp (As alp::Iterator is in alp), __gnu_cxx and std.
Your View_iterator_base::const_iterator is invalid. View_iterator_base::const_interator::result_type is defined as decltype(Func{}(*std::vector<int>::const_iterator{})). std::vector<int>::const_iterator{} will be a vectors const iterator, so *std::vector<int>::const_iterator{} is a const int&. Func::operator() takes an int&, so this means that the expression is invalid. But it won't cause a compile time error if not used, for the reasons stated above. This means that your conversion operator is to an invalid type.
Since you don't define it as explicit, the conversion operator (To an invalid type) will be used to try and match it to the function parameters if they don't already match. Obviously this will finally instantiate the invalid type, so it will throw a compile time error.
My guess is that iostream includes string, which defines std::operator== for strings.
Here's an example without the std namespace: https://godbolt.org/z/-wlAmv
// Avoid including headers for testing without std::
template<class T> struct is_const { static constexpr const bool value = false; } template<class T> struct is_const<const T> { static constexpr const bool value = true; }
namespace with_another_equals {
struct T {};
bool operator==(const T&, const T&) {
return true;
}
}
namespace ns {
template<class T>
struct wrapper {
using invalid_wrapper = wrapper<typename T::invalid>;
operator invalid_wrapper() {}
};
template<class T>
bool operator==(const wrapper<T>&, const wrapper<T>&) {
return true;
}
}
template<class T>
struct with_invalid {
static_assert(!is_const<T>::value, "Invalid if const");
using invalid = with_invalid<const T>;
};
template<class T>
void test() {
using wrapped = ns::wrapper<with_invalid<T>>;
wrapped a;
wrapped b;
bool x = operator==(a, b);
bool y = ns::operator==(a, b);
}
template void test<int*>();
// Will compile if this line is commented out
template void test<with_another_equals::T>();
Note that just declaring operator const_iterator() should instantiate the type. But it doesn't because it is within templates. My guess is that it is optimised out (where it does compile because it's unused) before it can be checked to show that it can't compile (It doesn't even warn with -Wall -pedantic that it doesn't have a return statement in my example).
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I get a compiler regarding apply_visitor within the current operator.
I tested all the apply_visitor outside of that method and it works perfectly fine. Just when trying to use it within that method it runs into a bunch of issues.
The error message is confusing me.
So, Why is trying to use apply_visitor for a different visitor is running into problems within the current visitor?
Here the Snippet of the code that have give me the errors:
typedef boost::make_recursive_variant<string, int, vector<boost::recursive_variant_ > >::type ObjectE;
class ReturnType : public boost::static_visitor<string> {
public:
string operator()(string &s) { return "string"; }
string operator()(int i) {return "int";}
string operator()(std::vector<ObjectE> const &v) {return "vector";}
};
class ReturnVal : public boost::static_visitor<string> {
public:
string operator()(string &s) { return s; }
string operator()(int i) {return to_string(i);}
string operator()(std::vector<ObjectE> const &v) {return "vector";}
};
class ReturnV : public boost::static_visitor<vector<ObjectE>> {
public:
vector<ObjectE> operator()(string &s){ return {};}
vector<ObjectE> operator()(int i) {return {};}
vector<ObjectE> operator()(vector<ObjectE> const &v) {return v;}
};
struct create_Str {
using result_type = void;
std::ostream & out;
template <typename T> void call(T const &v) { return operator()(v);}
template <typename... Ts> void operator()(boost::variant<Ts...> const &v) {
return boost::apply_visitor(*this, v);
}
void operator()(int i) { out << i; }
void operator()(std::string const &s) { out << s; }
template <typename... Ts> void operator()(std::vector<Ts...> const &v) {
string name = boost::apply_visitor(ReturnVal(), v[0]);
if (v.size() == 3 && isOp(name)) {
}
else if (v.size() == 3 && isListCons(name)) {
call(v[1]);
ObjectE tail = v[2];
for (;;) {
if ("[]" == boost::get<string>(tail) || "nil" == boost::get<string>(tail)) {
break;
}
if ( !(boost::apply_visitor(ReturnType(), tail) == "vector")) {
}
vector<ObjectE> list = boost::apply_visitor(ReturnV(), v[2]);;
if (!(list.size() == 3 && isListCons(boost::apply_visitor(ReturnVal(), list[0])))) {
}
}
}
}
};
At first, I thought maybe
vector<ObjectE> list = v[2];
was the issue. So I created a visitor who will return a vector.
However, it seem that most of the errors are :
error: no match for call to '(const ReturnVal) (std::__cxx11::basic_string<char>&)'
which I'm not sure what it mean.
Can someone explain to me what the issue is?
Hah. Look back at my older answer to you:
Calls like
boost::apply_visitor(ReturnType(), tail)
call pass the visitor as a temporary, so it can only bind to a const&. This means that all call-operator overloads required must be const-qualified, because otherwise they won't apply, as you're being told:
Live On Coliru
#include <boost/variant.hpp>
struct Ok : boost::static_visitor<> {
void operator()(std::string const&) const {}
void operator()(int) const {}
};
struct NotWorkingWithTemporaries : boost::static_visitor<> {
void operator()(std::string const&) const {}
void operator()(int) {} // whoops, missing const-qualifier
};
int main() {
boost::variant<std::string, int> v;
boost::apply_visitor(Ok{}, v);
//boost::apply_visitor(NotWorkingWithTemporaries{}, v); // COMPILE ERROR
// however, this works:
NotWorkingWithTemporaries not_a_temporary;
boost::apply_visitor(not_a_temporary, v);
}
Compiles. Ucommenting the line commented with // COMPILE RROR gives:
Live On Coliru
In file included from /usr/local/include/boost/variant.hpp:17:0,
from main.cpp:1:
/usr/local/include/boost/variant/variant.hpp: In instantiation of 'boo...
/usr/local/include/boost/variant/detail/visitation_impl.hpp:114:9: r...
/usr/local/include/boost/variant/detail/visitation_impl.hpp:154:41: ...
/usr/local/include/boost/variant/detail/visitation_impl.hpp:238:5: r...
/usr/local/include/boost/variant/variant.hpp:2390:48: required from ...
/usr/local/include/boost/variant/variant.hpp:2404:43: required from ...
/usr/local/include/boost/variant/variant.hpp:2429:52: required from ...
/usr/local/include/boost/variant/detail/apply_visitor_unary.hpp:84:43:...
main.cpp:17:56: required from here
/usr/local/include/boost/variant/variant.hpp:1046:24: error: no match ...
return visitor_(operand);
~~~~~~~~^~~~~~~~~
main.cpp:9:10: note: candidate: void NotWorkingWithTemporaries::operat...
void operator()(std::string const&) const {}
^~~~~~~~
main.cpp:9:10: note: no known conversion for argument 1 from 'int' t...
main.cpp:10:10: note: candidate: void NotWorkingWithTemporaries::opera...
void operator()(int) {} // whoops, missing const-qualifier
^~~~~~~~
main.cpp:10:10: note: passing 'const NotWorkingWithTemporaries*' as ...
In file included from /usr/local/include/boost/variant.hpp:17:0,
from main.cpp:1:
/usr/local/include/boost/variant/variant.hpp:1046:32: error: return-st...
return visitor_(operand);
Skip the required from chain, scan for error: first and then notice the note: that says:
main.cpp:10:10: note: candidate: void NotWorkingWithTemporaries::operator()(int) <near match>
void operator()(int) {} // whoops, missing const-qualifier
^~~~~~~~
main.cpp:10:10: note: passing 'const NotWorkingWithTemporaries*' as 'this' argument discards qualifiers
It's pretty clear once you look for it: passing 'const NotWorkingWithTemporaries*' as 'this' argument discards qualifiers. The only thing you need to know is const is known as a qualifier¹.
¹ const, volatile and rvalue-ref (&&)
OTHER REMARKS
Trying to get the rest of your non-self-contained question code to compile reveals similar issues with the std::string overloads:
std::string operator()(std::string const & /*s*/) const { return "std::string"; }
(note std::string const& instead of std::string&).
Other than that... it look as though you're abusing vectors to represent Expressions. Why not make it strong typed and a lot less error-prone?
See e.g. Building a Custom Expression Tree in Spirit:Qi (Without Utree or Boost::Variant)
Is there any simple solution how to convert vector<cv::Point2d> to vector<cv::Point>? something like here C++ convert vector<int> to vector<double> ?
This types are templated :
typedef Point_<double> Point2d;
typedef Point_<int> Point2i;
typedef Point2i Point;
/*!
template 2D point class.
The class defines a point in 2D space. Data type of the point coordinates is specified
as a template parameter. There are a few shorter aliases available for user convenience.
See cv::Point, cv::Point2i, cv::Point2f and cv::Point2d.
*/
template<typename _Tp> class Point_
{
public:
typedef _Tp value_type;
// various constructors
Point_();
Point_(_Tp _x, _Tp _y);
Point_(const Point_& pt);
Point_(const CvPoint& pt);
Point_(const CvPoint2D32f& pt);
Point_(const Size_<_Tp>& sz);
Point_(const Vec<_Tp, 2>& v);
Point_& operator = (const Point_& pt);
//! conversion to another data type
template<typename _Tp2> operator Point_<_Tp2>() const;
//! conversion to the old-style C structures
operator CvPoint() const;
operator CvPoint2D32f() const;
operator Vec<_Tp, 2>() const;
//! dot product
_Tp dot(const Point_& pt) const;
//! dot product computed in double-precision arithmetics
double ddot(const Point_& pt) const;
//! cross-product
double cross(const Point_& pt) const;
//! checks whether the point is inside the specified rectangle
bool inside(const Rect_<_Tp>& r) const;
_Tp x, y; //< the point coordinates
};
You can do exactly as described there using vector range constructor:
#include <opencv2\opencv.hpp>
#include <vector>
using namespace cv;
using namespace std;
int main()
{
vector<Point2d> vd{ { 1.1, 2.2 }, { 3.3, 4.4 }, {5.5, 6.6} };
vector<Point> v(vd.begin(), vd.end());
// Print for debug
copy(vd.begin(), vd.end(), ostream_iterator<Point2d>(cout, " "));
cout << endl;
copy(v.begin(), v.end(), ostream_iterator<Point>(cout, " "));
return 0;
}
This will work since you can build a Point from a Point2d with:
template<typename _Tp> template<typename _Tp2> inline Point_<_Tp>::operator Point_<_Tp2>() const
{ return Point_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y)); }
Since there is not conversion from cv::Point2D to cv::Point I would suggest a lambda (untested):
vector<cv::Point2d> src ;
vector<cv::Point> dest ;
std::copy(src.begin(),
src.end(),
[&dest](const cv::Point2d &item) {
dest.push_back(cv::Point(pt.x, pt.y)) ;}) ;
So I'm still some what new to C++ programming and very new at templates. I am trying to make a basic template class (a node if you will) that holds some generic data and a double. I then want to make another class contain a set of the previously mentioned template class.
Im having trouble with the less-than operator as its going to server as my comparator.
Node&Tree.h
#ifndef _POINTNODE_H_
#define _POINTNODE_
#include <set>
template<typename T>
class PointNode {
public:
PointNode(double p){ m_point = p;}
~PointNode();
bool operator < (const &PointNode<T> p1) const;
private:
const double m_point;
T *m_data;
};
template <typename T>
class PointTree {
public:
PointTree();
~PointTree();
private:
std::set<PointNode<T> > tree;
};
#endif
Node&Tree.cpp
#inlcude "Node&Tree.h"
#include <set>
template<typename T>
bool PointNode<T>:: operator < (const &PointNode<T> p1) const{
return m_point < p1.m_point;
}
Im getting the folowing errors
Node&Tree.cpp:5:39: error: ISO C++ forbids declaration of ‘parameter’ with no type [- fpermissive]
Node&Tree.cpp:5:39: error: expected ‘,’ or ‘...’
Node&Tree.cpp:5:6: error: prototype for ‘bool PointNode<T>::operator<(const int&) const’ does not match any in class ‘PointNode<T>’
Node&Tree.h:15:8: error: candidate is: bool PointNode<T>::operator<(const int&)"
This is largely unimplemented but I just wanted to get the basics to compile at least... And any pointers on the code or if you think I'm going about this all wrong please tell me!
Any help would be amazing!
bool PointNode<T>:: operator < (const &PointNode<T> p1) const
should be:
bool PointNode<T>:: operator < (const PointNode<T>& p1) const
You put the reference & in the wrong position, so you have that forbids declaration of parameter error. Another place has the same error.
bool operator < (const &PointNode<T> p1) const;
should be
bool operator < (const PointNode<T>& p1) const;
Make PointNode object as reference
bool operator < (const PointNode<T>& p1) const;
And its defination
template<typename T>
bool PointNode<T>:: operator < (const PointNode<T>& p1) const{
return m_point < p1.m_point;
}
this will fix the problem.