0

I am a 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.

leo
  • 61
  • 1
  • 9
  • What are you trying to do with the strings in vector? – stefanB Oct 29 '10 at 03:15
  • bind and lambda both have placeholders `_1`, bind in anonymous namespace, lambda in lambda namespace. try not using entire boost::lambda namespace – Anycorn Oct 29 '10 at 03:17

3 Answers3

1

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(); });
James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • Thanks, the application works, but I am a little confused with this code : (void (std::vector::*)(const int&))&std::vector::push_back. I need to learn more about that. – leo Oct 31 '10 at 06:49
  • @user: `&std::vector::push_back` takes the address of the named member function. The part that precedes it is a cast, just as if you had said `(int)3.0`, which casts the double value `3.0` to type `int`. In this case, we are casting to the type "pointer to a function that is a member of `std::vector` and that takes one argument of type `const int&` and returns `void`. – James McNellis Oct 31 '10 at 06:53
  • I tried lambda expressions std::for_each(strings.begin(), strings.end(), [&](const std::string& s) { sizes.push_back(s.size()); }); and std::transform(...) but yielded syntax error:"[" "]", so I missed some header file or other reasons? – leo Oct 31 '10 at 09:18
  • @leo: Your compiler may not support lambda expressions. The latest versions of Visual C++, Intel C++, and g++ all support them. – James McNellis Oct 31 '10 at 15:51
  • I am sorry that I ran it on both VS2005 and ubuntu 10.04 with g++ 4.4.3, and both gave that error.Should I specify namespace or compile code with some libraries? – leo Nov 01 '10 at 02:01
  • @leo: Visual C++ 2010 is the first version that supports lambdas (they weren't much more than a proposed language feature in 2005). If I recall correctly, g++ 4.5 is the first version that fully supports lambdas (I could be wrong there; I don't use g++). Intel C++ 11 was the first version of that compiler to support lambdas. – James McNellis Nov 01 '10 at 02:09
  • maybe that was the reason, I found someone had the same error on forum, and thanks again. – leo Nov 01 '10 at 02:34
0
  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);
Anycorn
  • 50,217
  • 42
  • 167
  • 261
0

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;
}
stefanB
  • 77,323
  • 27
  • 116
  • 141