views:

67

answers:

3

Hello, 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.

A: 
  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);
aaa
When I tried this I got not values in `sizes` (g++ (GCC) 4.1.2) ...
stefanB
I run on windows vs2005, following answers all works.
leo
A: 

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).

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
leo
James McNellis
Aha I see. thanks a lot
leo
I tried lambda expressions std::for_each(strings.begin(), strings.end(), [ }); and std::transform(...) but yielded syntax error:"[" "]", so I missed some header file or other reasons?
leo
@leo: Your compiler may not support lambda expressions. The latest versions of Visual C++, Intel C++, and g++ all support them.
James McNellis
A: 

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