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)) ;}) ;
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();
}
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;
}
and thanks for any input. I have a large dataset I am trying to manipulate. I am holding active elements in a list, and removing them when they become inactive. I want to hold all elements active and inactive in some data structure. Currently trying a map or an unordered_map, but am welcome to any suggestions.
I am compiling with
clang++ -std=c++11 -Wall -Wextra
When trying map:
#include <map>
std::map <class1, std::string> fullMap;
//and later...
for (std::list<class1>::iterator x = l.begin(); x != l.end(); x++)
{
fullMap[(*x)] = s
}
output reads:
error: invalid operands to binary expression ('const class1' and
'const class1') { return __x < __y; }
Even though I have overloaded the less than operator for class1.
This error originates at the overloaded bracket operators for map.
To circumvent I tried storing in an unordered_map.
#include <unordered_map>
std::unordered_map <class1, std::string> fullMap;
and the program fails at the initialization of fullMap with the even more confusing:
/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.4/include/g++-v4/bits/hashtable_policy.h:830:23:
error: implicit instantiation of undefined template
'std::hash'
bool __use_ebo = !__is_final(_Tp) && __is_empty(_Tp)>
^
/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.4/include/g++-v4/bits/hashtable_policy.h:1073:15: note: in instantiation of default argument for
'_Hashtable_ebo_helper<1, std::hash >' required here
private _Hashtable_ebo_helper<1, _H1>,
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.4/include/g++-v4/bits/hashtable_policy.h:1403:12: note: in instantiation of template class
'std::__detail::_Hash_code_base >, std::__detail::_Select1st, std::hash, std::__detail::_Mod_range_hashing,
std::__detail::_Default_ranged_hash, true>' requested here : public
_Hash_code_base<_Key, _Value, _ExtractKey, _H1, _H2, _Hash,
^
/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.4/include/g++-v4/bits/hashtable.h:175:14:
note: in instantiation of template class
'std::__detail::_Hashtable_base >, std::__detail::_Select1st, std::equal_to, std::hash,
std::__detail::_Mod_range_hashing,
std::__detail::_Default_ranged_hash,
std::__detail::_Hashtable_traits >' requested here
: public __detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal,
^
/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.4/include/g++-v4/bits/unordered_map.h:100:18:
note: in instantiation of template class 'std::_Hashtable >,
std::allocator > >, std::__detail::_Select1st, std::equal_to, std::hash, std::__detail::_Mod_range_hashing,
std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy,
std::__detail::_Hashtable_traits >' requested here
_Hashtable _M_h;
^
main.cpp:34:44: note: in instantiation of template class
'std::unordered_map,
std::hash, std::equal_to,
std::allocator > > >' requested here std::unordered_map fullMap;
^
/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.4/include/g++-v4/bits/functional_hash.h:58:12:
note: template is declared here
struct hash;
I tried to cut the code down only to the relevant chunks, but let me know if more information is needed. Thanks for reading, any help is appreciated.
//
// class1.hpp
// class
//
// Created by Roach on 9/3/16.
// Copyright © 2016 Roach. All rights reserved.
//
#ifndef class1_hpp
#define class1_hpp
#include <iostream>
#include <sstream>
#include <iomanip>
#include <ctime>
class class1
{
public:
class1 ();
class1 (const class1& t); // copy constructor
~class1 (); // destructor
class1& operator = (const class1& t); // assignment operator
bool operator == (const class1& t); // comparison operator
void setSetting2 (std::string t);
void setSetting1 (std::string p);
void setSetting3 (double d);
void setSetting4 (double d);
std::tm getTime () const;
std::string getSetting2 () const;
double getSetting3 () const;
double getSetting4 () const;
std::string getSetting1 () const;
void setSetting3End (double d);
void setSetting4End (double d);
double getSetting3End () const;
double getSetting4End () const;
double getSetting3flag () const;
double getSetting4flag () const;
double getSetting3final () const; // in pips
double getSetting4final () const; // in pips
void processList (class1::class1 t);
void setNew ();
//void dump (std::ostream& os) const;
private:
std::string setting1;
double setting4;
double setting3;
std::tm setting2;
double setting4End_;
double setting3End_;
bool setting4Flag_;
bool setting3Flag_;
double setting4final_; // in pips
double setting3final_; // in pips
};
// stream extraction operator
std::ostream& operator << (std::ostream& os, const class1& s);
std::istream& operator >> (std::istream& is, class1& t);
endif /* class1_hpp */
The following is my overloaded less than operator (I know it isn't the most succinct or efficient):
bool class1::operator< (const class1& t)
{
if (this->time_.tm_year < t.time_.tm_year) {return true;}
else if (this->time_.tm_year > t.time_.tm_year) {return false;}
else if (this->time_.tm_mon < t.time_.tm_mon) {return true;}
else if (this->time_.tm_mon > t.time_.tm_mon) {return false;}
else if (this->time_.tm_mday < t.time_.tm_mday) {return true;}
else if (this->time_.tm_mday > t.time_.tm_mday) {return false;}
else if (this->time_.tm_hour < t.time_.tm_hour) {return true;}
else if (this->time_.tm_hour > t.time_.tm_hour) {return false;}
else if (this->time_.tm_min < t.time_.tm_min) {return true;}
else if (this->time_.tm_min > t.time_.tm_min) {return false;}
else if (this->time_.tm_sec < t.time_.tm_sec) {return true;}
else {return false;}
}
The issue is that std::map<key_type, value_type> requires a properly defined operator< for key_type, in this case your operator< is not const specified so it is incompatible with std::map as this data structure requires that the comparator not alter the key object in any way. Thus the solution is to mark class1::operator< as const.
The second error notes that no hash function-object has been applied for use with std::unordered_map, this would require the following framework:
auto class1_hasher = [](const class1& c) -> std::size_t { return {some hash based on c}; }
std::unordered_map<class1, std::string, decltype(class1_hasher)> um;
I think the issue here is that you're breaking the preconditions required of the std::map and std::unordered_map interfaces.
In a std::map, the key type needs to be able to be compared using the less-than operator. This means that you either need to provide an overload of operator <, or provide a custom comparator when you're using the std::map type. Since you didn't provide a way of doing this with your type, the internal implementation of std::map wasn't able to make an expression of the form
somethingOfTypeClass1 < somethingElseOfTypeClass1
compile, hence your error message.
When you switched to std::unordered_map, you ran into trouble because, in order to store something as a key in an std::unordered_map, you need to specialize the std::hash template on your custom type because the internal works of an unordered_map require that the type is hashable. That's the second error you got.
To fix this issue, either
Define a custom operator < or comparator type for class1, then use std::map, or
Define a custom std::hash for class1, then use std::unordered_map.
Its difficult to suggest best data structure until we know the functionality requirement. But the Below code is working for me on GCC 4.9.3.
Please check your include files and syntax.
#include <iostream>
#include <string>
#include <map>
#include <unordered_map>
#include <list>
using namespace std;
int main()
{
//LIST
std::list<int> myList;
myList.push_front(1);
myList.push_front(2);
myList.push_front(3);
myList.push_front(4);
//STRING
string s = "Test";
//MAP
std::map <int, std::string> fullMap;
for (std::list<int>::iterator x = myList.begin(); x != myList.end(); x++)
{
fullMap.insert(std::make_pair(*x,s));
}
//UNORDERED MAP
std::unordered_map <int, std::string> fullUnorderedMap;
for (std::list<int>::iterator y = myList.begin(); y != myList.end(); y++)
{
fullUnorderedMap.insert(std::make_pair(*y,s));
}
//PRINTING
for(auto it = fullMap.begin(); it != fullMap.end(); ++it)
{
cout<<it->first<<" "<<it->second<<endl;
}
for(auto it = fullUnorderedMap.begin(); it != fullUnorderedMap.end(); ++it)
{
cout<<it->first<<" "<<it->second<<endl;
}
}
I would like to use BOOST_FOREACH with one of legacy container type in my code base which I cannot change.
I have the following methods defined on that type:
.length() returning the current number of elements in the container
.operator[](unsigned i) returning a reference to element under index i
I know that I need to make my container type to satisfy Single Pass Range Concept as the boost documentation suggest but I am somehow lost since I cannot modify the type.
Any hints/solutions will be useful.
EDIT
I tried to go with suggestion but this code
struct wrapper
{
struct iterator : std::iterator<std::forward_iterator_tag, ObservationReport>
{
iterator(ObservationReportList* p, int i) : pnt_(p), i_(i) {}
ObservationReport& operator*() {
return (*pnt_)[i_];
}
iterator& operator++() {
++i_;
return *this;
}
bool operator==(const iterator& r) const {
return i_ == r.i_;
}
bool operator!=(const iterator& r) const {
return i_ != r.i_;
}
ObservationReportList* pnt_;
int i_;
};
wrapper(ObservationReportList & n)
: begin_( boost::addressof(n), 0 )
, end_( boost::addressof(n), n.length() )
{}
iterator begin() { return begin_; }
iterator end() { return end_; }
iterator begin_, end_;
};
// usage
ObservationReportList reportList;
// filling reportList
BOOST_FOREACH(ObservationReport o, wrapper(reportList))
{
}
gives me the following compiler errors:
In file included from /usr/include/boost159/boost/foreach.hpp:71:0,
from test/src/MessageFillerTest.cpp:18:
/usr/include/boost159/boost/mpl/eval_if.hpp: In instantiation of ‘struct boost::mpl::eval_if<mpl_::bool_<true>, boost::range_const_iterator<wrapper, void>, boost::range_mutable_iterator<wrapper, void> >’:
/usr/include/boost159/boost/foreach.hpp:359:13: required from ‘struct boost::foreach_detail_::foreach_iterator<wrapper, mpl_::bool_<true> >’
/usr/include/boost159/boost/foreach.hpp:679:1: required by substitution of ‘template<class T> boost::foreach_detail_::auto_any<typename boost::foreach_detail_::foreach_iterator<T, mpl_::bool_<true> >::type> boost::foreach_detail_::begin(
boost::foreach_detail_::auto_any_t, boost::foreach_detail_::type2type<T, mpl_::bool_<true> >*, bool*) [with T = wrapper]’
test/src/MessageFillerTest.cpp:206:3: required from here
/usr/include/boost159/boost/mpl/eval_if.hpp:38:31: error: no type named ‘type’ in ‘boost::mpl::eval_if<mpl_::bool_<true>, boost::range_const_iterator<wrapper, void>, boost::range_mutable_iterator<wrapper, void> >::f_ {aka struct boost::ran
ge_const_iterator<wrapper, void>}’
typedef typename f_::type type;
^
In file included from test/src/MessageFillerTest.cpp:18:0:
test/src/MessageFillerTest.cpp: In member function ‘virtual void MessageFiller_XXX_Test::TestBody()’:
/usr/include/boost159/boost/foreach.hpp:1020:39: error: no matching function for call to ‘begin(const boost::foreach_detail_::auto_any_base&, boost::foreach_detail_::type2type<wrapper, mpl_::bool_<true> >*, bool*)’
, BOOST_FOREACH_SHOULD_COPY(COL))
^
/usr/include/boost159/boost/foreach.hpp:1101:77: note: in expansion of macro ‘BOOST_FOREACH_BEGIN’
if (boost::foreach_detail_::auto_any_t BOOST_FOREACH_ID(_foreach_cur) = BOOST_FOREACH_BEGIN(COL)) {} else \
^
test/src/MessageFillerTest.cpp:206:3: note: in expansion of macro ‘BOOST_FOREACH’
BOOST_FOREACH(ObservationReport o, wrapper(reportList))
^
/usr/include/boost159/boost/foreach.hpp:660:1: note: candidate: template<class T, class C> boost::foreach_detail_::auto_any<typename boost::foreach_detail_::foreach_iterator<T, C>::type> boost::foreach_detail_::begin(boost::foreach_detail_
::auto_any_t, boost::foreach_detail_::type2type<T, C>*, mpl_::true_*)
begin(auto_any_t col, type2type<T, C> *, boost::mpl::true_ *) // rvalue
^
/usr/include/boost159/boost/foreach.hpp:660:1: note: template argument deduction/substitution failed:
/usr/include/boost159/boost/foreach.hpp:964:46: note: cannot convert ‘boost::foreach_detail_::should_copy_impl(((mpl_::bool_<false>*)0u), ((mpl_::bool_<false>*)0u), (& _foreach_is_rvalue206))’ (type ‘bool*’) to type ‘mpl_::true_* {aka mp
l_::bool_<true>*}’
(boost::foreach_detail_::should_copy_impl( \
^
/usr/include/boost159/boost/foreach.hpp:1020:9: note: in expansion of macro ‘BOOST_FOREACH_SHOULD_COPY’
, BOOST_FOREACH_SHOULD_COPY(COL))
^
/usr/include/boost159/boost/foreach.hpp:1101:77: note: in expansion of macro ‘BOOST_FOREACH_BEGIN’
if (boost::foreach_detail_::auto_any_t BOOST_FOREACH_ID(_foreach_cur) = BOOST_FOREACH_BEGIN(COL)) {} else \
^
test/src/MessageFillerTest.cpp:206:3: note: in expansion of macro ‘BOOST_FOREACH’
BOOST_FOREACH(ObservationReport o, wrapper(reportList))
^
/usr/include/boost159/boost/foreach.hpp:668:1: note: candidate: template<class T, class C> boost::foreach_detail_::auto_any<typename boost::foreach_detail_::foreach_iterator<T, C>::type> boost::foreach_detail_::begin(boost::foreach_detail_
::auto_any_t, boost::foreach_detail_::type2type<T, C>*, mpl_::false_*)
begin(auto_any_t col, type2type<T, C> *, boost::mpl::false_ *) // lvalue
^
/usr/include/boost159/boost/foreach.hpp:668:1: note: template argument deduction/substitution failed:
/usr/include/boost159/boost/foreach.hpp:964:46: note: cannot convert ‘boost::foreach_detail_::should_copy_impl(((mpl_::bool_<false>*)0u), ((mpl_::bool_<false>*)0u), (& _foreach_is_rvalue206))’ (type ‘bool*’) to type ‘mpl_::false_* {aka m
pl_::bool_<false>*}’
(boost::foreach_detail_::should_copy_impl( \
^
/usr/include/boost159/boost/foreach.hpp:1020:9: note: in expansion of macro ‘BOOST_FOREACH_SHOULD_COPY’
, BOOST_FOREACH_SHOULD_COPY(COL))
^
/usr/include/boost159/boost/foreach.hpp:1101:77: note: in expansion of macro ‘BOOST_FOREACH_BEGIN’
if (boost::foreach_detail_::auto_any_t BOOST_FOREACH_ID(_foreach_cur) = BOOST_FOREACH_BEGIN(COL)) {} else \
^
test/src/MessageFillerTest.cpp:206:3: required from here
/usr/include/boost159/boost/foreach.hpp:768:1: error: no type named ‘type’ in ‘struct boost::foreach_detail_::foreach_reference<wrapper, mpl_::bool_<true> >’
A wrapper can provide the required interface.
Note that in this example, operator[] of nasty_thing returns a reference to an int in an array of consecutive ints.
It this is not the case, we need to make the wrapper work in terms of an index.
#include <utility>
#include <memory>
//
// a nasty thing that contains consecutive ints
struct nasty_thing
{
int& operator[](int i);
int length();
};
// because we are dealing in consecutive ints, we can approximate an iterator with a pointer
struct wrapper
{
using iterator = int*;
wrapper(nasty_thing& n)
: begin_(std::addressof(n[0]))
, end_(begin_ + n.length())
{}
iterator begin() const { return begin_; }
iterator end() const { return end_; }
iterator begin_, end_;
};
extern nasty_thing& nt;
int main()
{
// simulate BOOST_FOREACH
for (auto& i : wrapper(nt))
{
}
}
This is the version in which nasty_thing does not represent contiguous memory:
#include <utility>
#include <memory>
#include <boost/foreach.hpp>
//
// a nasty thing that contains consecutive ints
struct nasty_thing
{
int& operator[](int i);
int length();
};
struct wrapper
{
struct iterator : std::iterator<std::forward_iterator_tag, int>
{
iterator(nasty_thing* p, int i) : pnt_(p), i_(i) {}
int& operator*() const {
return (*pnt_)[i_];
}
iterator& operator++() {
++i_;
return *this;
}
bool operator==(const iterator& r) const {
return i_ == r.i_;
}
bool operator!=(const iterator& r) const {
return i_ != r.i_;
}
nasty_thing* pnt_;
int i_;
};
// needed by BOOST_FOREACH
using const_iterator = iterator;
wrapper(nasty_thing& n)
: begin_{ std::addressof(n), 0 }
, end_{std::addressof(n), n.length()}
{}
iterator begin() const { return begin_; }
iterator end() const { return end_; }
iterator begin_, end_;
};
extern nasty_thing& nt;
int main()
{
// simulate BOOST_FOREACH
BOOST_FOREACH(auto& i, wrapper(nt))
{
}
}
There are docs:
http://www.boost.org/doc/libs/1_61_0/doc/html/foreach/extensibility.html
That walk you through extending the range concept to a custom container without modfying the container.
Create a range_begin and range_end free functions that take your container type in th container's namespace.
In namespace boost, specialize the traits class(es) that tells boost the iterator type:
template<> struct range_mutable_iterator< your::type::here > {
typedef your_iterator_type type;
};
template<> struct range_const_iterator< your::type::here > {
typedef your_iterator_type type;
};
And done.
This could probably be done with specializing boost::range_iterator<X>::type and boost::range_iterator<const X>::type and direct overloads of boost::begin/boost::end or ADL begin/end overloads, but I thought I'd use the documented extensibility path I found.
I will just post it for reference as Richard Hodges got it almost right.
struct wrapper
{
struct iterator : std::iterator<std::forward_iterator_tag, ObservationReport>
{
iterator(ObservationReportList* p, int i) : pnt_(p), i_(i) {}
ObservationReport& operator*() {
return (*pnt_)[i_];
}
iterator& operator++() {
++i_;
return *this;
}
bool operator==(const iterator& r) const {
return i_ == r.i_;
}
bool operator!=(const iterator& r) const {
return i_ != r.i_;
}
ObservationReportList* pnt_;
int i_;
};
typedef iterator const_iterator; // essential (in one way or another)
// http://www.boost.org/doc/libs/1_61_0/libs/range/doc/html/range/concepts/single_pass_range.html
wrapper(ObservationReportList & n)
: begin_( boost::addressof(n), 0 )
, end_( boost::addressof(n), n.length() )
{}
iterator begin() { return begin_; }
iterator end() { return end_; }
iterator begin() const { return begin_; } // essential for Single Pass concept
iterator end() const { return end_; } // essential for Single Pass concept
iterator begin_, end_;
};
// usage
ObservationReportList reportList;
// filling reportList
BOOST_FOREACH(ObservationReport o, wrapper(reportList))
{
}
So basically we missed const_iterator type definition (here only a typedef) and const versions of begin() and end()
I am using a deque so I can generate rolling averages and variances for my data. I store n and n^2 as a pair in the deque and then use accumulate with my own operator+().
#include <deque>
#include <numeric>
#include <utility>
template <typename T1, typename T2>
std::pair<T1,T2> operator+(const std::pair<T1,T2>& lhs, const std::pair<T1,T2>& rhs)
{
return std::pair<T1,T2>(lhs.first + rhs.first, lhs.second + rhs.second);
}
namespace resource
{
template <typename T>
class rollingStats
{
public:
rollingStats(unsigned int n, const T& val):
xs(n, std::pair<T,T>(val, val*val))
{;}
~rollingStats()
{;}
T getMean(void) const
{
std::pair<T,T> sum = std::accumulate(xs.begin(), xs.end(), std::pair<T,T>((T)0,(T)0));
return sum.first / xs.size();
}
T getVar(void) const
{
const unsigned int n = xs.size();
std::pair<T,T> sum = std::accumulate(xs.begin(), xs.end(), std::pair<T, T > ((T)0,(T)0));
return ((n * sum.second - sum.first*sum.first) / (n * n));
}
void addValue(const T& val)
{
xs.pop_front();
xs.push_back(std::pair<T,T>(val,val*val) );
}
const std::deque<std::pair<T,T> >& getXs(void) const {return xs;}
private:
std::deque<std::pair<T,T> > xs;
};
}
I get a compilation error using g++ 4.1.2 which I can't resolve.
[ CC ] resource/UnitTest: rollingStats_Test.o
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_numeric.h: In function ‘_Tp std::accumulate(_InputIterator, _InputIterator, _Tp) [with _InputIterator = std::_Deque_iterator<std::pair<float, float>, const std::pair<float, float>&, const std::pair<float, float>*>, _Tp = std::pair<float, float>]’:
../rollingStats.hpp:45: instantiated from ‘T resource::rollingStats<T>::getMean() const [with T = float]’
rollingStats_Test.cpp:98: instantiated from here
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_numeric.h:89: error: no match for ‘operator+’ in ‘__init + __first.std::_Deque_iterator<_Tp, _Ref, _Ptr>::operator* [with _Tp = std::pair<float, float>, _Ref = const std::pair<float, float>&, _Ptr = const std::pair<float, float>*]()’
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_bvector.h:267: note: candidates are: std::_Bit_iterator std::operator+(ptrdiff_t, const std::_Bit_iterator&)
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_bvector.h:353: note: std::_Bit_const_iterator std::operator+(ptrdiff_t, const std::_Bit_const_iterator&)
make: *** [rollingStats_Test.o] Error 1
What have I got wrong here? Do I need to add my own functor instead of relying on the STL alone?
thanks
std::pair doesn't have an operator+, and you haven't provided a way for std::accumulate to call your implementation of operator+.
I would wrap the functionality you provided in operator+ in a functor...
template <typename T1, typename T2> struct pair_sum : public std::binary_function< std::pair<T1,T2>, std::pair<T1,T2>, std::pair<T1,T2> >
{
std::pair<T1,T2> operator()(const std::pair<T1,T2>& lhs, const std::pair<T1,T2>& rhs)
{
return std::pair<T1,T2>(lhs.first + rhs.first, lhs.second + rhs.second);
}
};
...and use that by calling the version of std::accumulate that takes 4 arguments:
std::pair<T,T> sum = std::accumulate(xs.begin(), xs.end(), std::make_pair((T)0,(T)0), pair_sum<T,T>());
Quoting Oliver Seiler's comment:
I can see three options: use the form of accumulate that takes a binary function, using an add_pair function you'd need to write (probably the simplest option); subclass std::pair and give it addition operators (feels dirty); add a new struct/class that either has a pair or just has the members you need, and use that instead of the pair (probably the most flexible option).
[This is a community wiki answer. Feel free to edit to add corrections, samples, etc.]
You can get sum of pairs with help of boost::lambda:
#include <boost/lambda/bind.hpp>
#include <boost/lambda/construct.hpp>
template<typename T>
void summarize()
{
typedef std::pair<T, T> pt_t;
std::deque<pt_t> xs;
using namespace boost::lambda;
// fill xs with useful stuff
pt_t res = std::accumulate(
xs.begin(), xs.end(), std::make_pair(T(),T()),
bind( constructor<pt_t>(),
bind( std::plus<T>(), bind(&pt_t::first,_1), bind(&pt_t::first,_2) ),
bind( std::plus<T>(), bind(&pt_t::second,_1), bind(&pt_t::second,_2) )
) );
}