lambda bind problem?
I am a开发者_JAVA百科 new beginner with boost. And here is my test code,
using namespace boost::lambda;
std::vector<std::string> strings;
strings.push_back("Boost");
strings.push_back("C++");
strings.push_back("Libraries");
std::vector<int> sizes;
std::for_each(
strings.begin(),
strings.end(),
bind(
&std::vector<int>::push_back,
sizes,
bind<std::size_t>(&std::string::size, _1)));
std::for_each(sizes.begin(), sizes.end(), var(std::cout)<<_1);
build the project and yield an error:
error C2665: 'boost::lambda::function_adaptor::apply' : none of the 2 overloads could convert all the argument types
I wonder what's wrong? Really appreciate.
The first problem is that std::vector::push_back
is an overloaded function in C++0x (there is an overload with an lvalue reference parameter and an overload with an rvalue reference parameter).
The second problem is that the types of Standard Library member functions are unspecified: implementers are permitted to add extra parameters with default arguments to member functions, and they are permitted to add additional overloads of member functions, so any casting that you do would not be portable. The disambiguation example assumes that we ignore this second problem.
You will need to cast the pointer-to-member-function to the correct type, otherwise this won't work with a C++0x library implementation (the pointer-to-member-function will be ambiguous). You'll need:
(void (std::vector<int>::*)(const int&))&std::vector<int>::push_back
Using the C++0x functional library, the following works (it should work with Boost as well if you replace std::
with boost::
; I just can't test that):
std::for_each(
strings.begin(),
strings.end(),
std::bind(
(void (std::vector<int>::*)(const int&))&std::vector<int>::push_back,
std::ref(sizes),
std::bind(&std::string::size, std::placeholders::_1)));
Note that this is a real mess and it's much clearer just to use a for loop:
for(std::vector<int>::const_iterator i(strings.begin()); i != strings.end(); ++i)
{
sizes.push_back(i->size());
}
Or, if you have a compiler that supports lambda expressions:
std::for_each(strings.begin(), strings.end(),
[&](const std::string& s) { sizes.push_back(s.size()); });
Or, for more fun:
std::transform(strings.begin(), strings.end(), std::back_inserter(sizes),
[](const std::string& s) { return s.size(); });
namespace lambda = boost::lambda;
std::vector<std::string> strings;
strings.push_back("Boost");
strings.push_back("C++");
strings.push_back("Libraries");
std::vector<int> sizes;
std::for_each(
strings.begin(),
strings.end(),
bind(
&std::vector<int>::push_back,
sizes,
bind<std::size_t>(&std::string::size, _1)));
std::for_each(sizes.begin(), sizes.end(), lambda::var(std::cout)<< lambda::_1);
Or you can create your own function object:
template <typename T>
struct c_inserter
{
T& c;
c_inserter(T& c) : c(c) {}
void operator()(string& v) { c.push_back(v.size()); }
};
Then use it (note the ostream_iterator
and copy
replacing another lambda
):
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
#include <boost/lambda/lambda.hpp>
int main()
{
std::vector<std::string> strings;
strings.push_back("Boost");
strings.push_back("C++");
strings.push_back("Libraries");
std::vector<int> sizes;
std::for_each(
strings.begin(),
strings.end(),
c_inserter< vector<int> >(sizes));
copy(sizes.begin(), sizes.end(), ostream_iterator<int>(cout,":"));
cout << endl;
}
精彩评论