I've written some code which counts the number of elements of vector using a functor and the ref
and bind
templates from boost::
or std::
(for C++11) namespaces. I'm using a #define
to switch between boost::
and std::
namespaces. I'm using boost version 1.53 and my compilation command is g++ test.cpp -std=c++11
. I've tried with gcc versions 4.7.2 and 4.6.3 and I get the same errors with both.
I have 3 questions:
- I don't understand the error that is generated for Example 2.
- Is it possible to make code like this portable just by switching namespaces?
- Is there a good reference describing in detail the differences between the
std
andboost
versions ofbind
,ref
andfunction
? (I saw this question but the answers don't mentionref
orfunction
)
Thanks!
P.S. The example just illustrates my problem, I know about size()
for std::vector
:-)
//#define USE_STD
#ifdef USE_STD
#include <functional>
using namespace std::placeholders;
namespace impl = std;
#else
#include <boost/version.hpp>
#include <boost/bind.hpp>
#include <boost/ref.hpp>
namespace impl = boost;
#endif
#include <iostream>
#include <algorithm>
#include <vector>
class Item {
int id_;
public:
Item(int id) : id_(id) {};
};
template <typename ITEM>
class Counter {
int count_;
public:
// typedef void result_type; // adding this fixes Example 3 when impl=boost
Counter() : count_(0) {};
void operator()(ITEM* item) {count_++;}
int operator()() {return count_;}
};
//------------------------------------------------------------------------------
int main(int argc, char *argv[])
{
#ifndef USE_STD
std::cout << "BOOST_LIB_VERSION=" << BOOST_LIB_VERSION << std::endl;
#endif
// allocate
typedef std::vector<Item*> ItemVec;
ItemVec vec;
for (int i = 0; i < 9; ++i) {vec.push_back(new Item(i));}
// Example 1, works for BOTH
Counter<Item> f1;
f1 = std::for_each(vec.begin(), vec.end(), f1);
std::cout << "f1()=" << f1() << std::endl;
// Example 2, works with impl=std ONLY
// COMPILE ERROR with impl=boost: "no match for call to ‘(boost::reference_wrapper<Counter<Item> >) (Item*&)’"
Counter<Item> f2;
std::for_each(vec.begin(), vec.end(), impl::ref(f2));
std::cout << "f2()=" << f2() << std::endl;
// Example 3, works with impl=std ONLY
// COMPILE ERROR with impl=boost "no type named ‘result_type’ in ‘class Counter<Item>’"
// this can fixed by adding the typedef described above
Counter<Item> f3;
std::for_each(vec.begin(), vec.end(), impl::bind(impl::ref(f3), _1));
std::cout << "f3()=" << f3() << std::endl;
// clean up
for (ItemVec::iterator it = vec.begin(); it != vec.end(); ++it) {
delete *it;
}
vec.clear();
return 0;
}
Example 2 fails because
boost::reference_wrapper
doesn't have a memberoperator()
which forwards the argument(s), unlikestd::reference_wrapper
. As such, it's only useful for passing normal arguments by reference, not functions or functors which are expected to be called.Example 3 fails because Boost.Bind relies on a specific protocol to get the result type of the function or functor you pass, if you use the version without explicit return type. If you pass it a pointer-to-function or pointer-to-member-function, the returnd binder object has a nested
result_type
set to the return type of said PTF or PTMF. If you pass a functor, it needs a nestedresult_type
.std::bind
, on the other hand, simply has no nestedresult_type
if your functor doesn't have one.Note that you can, as I said, explicitly provide the result type to both
boost::bind
andstd::bind
:Which fixes the example and makes it compile.