Using boost::lambda::bind with std::transform

Hi, Would like to do the following with boost::lambda::bind #include <boost/lambda/lambda.hpp> #include <boost/lambda/bind.hpp> #include <algorithm> using namespace boost::lambda; struct Foo{ std::string get(){ ... } }; std::vector<Foo> array; // say it is already populated std::vector<std::string> tr; // the transformed instead using my handcrafted for loop, I would like to transform the std::list<Foo>::iterator endIter=array.end (); for (std::list<Foo>::iterator iter=array.begin(); iter!=endIter ;++iter) { noExtResults.push_back (iter.get().replace (0,5, "")); } I know it should be something like: std::transform (array.begin(), array.end (), std::back_inserter(tr), bind(&Foo::get, _1)); So here I'm stuck. The bind function will know to extract the string using get. But how to I get that string and do something like: bind(&std::string::replace (???)) Thanks in advance for your kind help, Kobi.

Kobi Cohen-Arazi wrote:
std::vector<Foo> array; // say it is already populated std::vector<std::string> tr; // the transformed instead using my handcrafted for loop, I would like to transform the std::list<Foo>::iterator endIter=array.end (); for (std::list<Foo>::iterator iter=array.begin(); iter!=endIter ;++iter) { noExtResults.push_back (iter.get().replace (0,5, "")); }
I know it should be something like: std::transform (array.begin(), array.end (), std::back_inserter(tr), bind(&Foo::get, _1));
So here I'm stuck. The bind function will know to extract the string using get. But how to I get that string and do something like: bind(&std::string::replace (???))
I'd use straight Boost.Bind, not Lambda. But the syntax is the same: std::transform(array.begin(), array.end(), std::back_inserter(tr), bind(&std::string::replace, bind(&Foo::get, _1), 0, 5, "")); Or you could use one of the special iterators from Boost.Iterator instead of the nested bind. Sebastian Redl

Hi, I've tried that, and I got a bunch of errors. I'm using boost::bind for that, not boost::lambda. Here is the error The following line: std::transform(array.begin(), array.end(), std::back_inserter(tr), bind(&std::string::replace, bind(&Foo::get, _1), 0, 5, "")); generates: error: no matching function for call to 'bind(<unknown type>, boost::_bi::bind_t<const std::string&, boost::_mfi::cmf0<const std::string&, Foo>, boost::_bi::list1<boost::arg<1> > >, int, uint32_t&, const char [1])' Kobi. On 4/26/06, Sebastian Redl <sebastian.redl@getdesigned.at> wrote:
Kobi Cohen-Arazi wrote:
std::vector<Foo> array; // say it is already populated std::vector<std::string> tr; // the transformed instead using my handcrafted for loop, I would like to transform the std::list<Foo>::iterator endIter=array.end (); for (std::list<Foo>::iterator iter=array.begin(); iter!=endIter ;++iter) { noExtResults.push_back (iter.get().replace (0,5, "")); }
I know it should be something like: std::transform (array.begin(), array.end (), std::back_inserter(tr), bind(&Foo::get, _1));
So here I'm stuck. The bind function will know to extract the string using get. But how to I get that string and do something like: bind(&std::string::replace (???))
I'd use straight Boost.Bind, not Lambda. But the syntax is the same:
std::transform(array.begin(), array.end(), std::back_inserter(tr), bind(&std::string::replace, bind(&Foo::get, _1), 0, 5, ""));
Or you could use one of the special iterators from Boost.Iterator instead of the nested bind.
Sebastian Redl _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

Kobi Cohen-Arazi wrote:
Hi,
I've tried that, and I got a bunch of errors. I'm using boost::bind for that, not boost::lambda. Here is the error
The following line: std::transform(array.begin(), array.end(), std::back_inserter(tr), bind(&std::string::replace, bind(&Foo::get, _1), 0, 5, ""));
generates: error: no matching function for call to 'bind(<unknown type>, boost::_bi::bind_t<const std::string&, boost::_mfi::cmf0<const std::string&, Foo>, boost::_bi::list1<boost::arg<1> > >, int, uint32_t&, const char [1])'
Hmmm ... the <unknown type> is suspicious. The problem might be that &std::string::replace is ambiguous, as it is overloaded. Try this: std::string & (std::string::*rep)(std::string::size_type, std::string::size_type, const char *) = &std::string::replace; std::transform(array.begin(), array.end(), std::back_inserter(tr), bind(rep, bind(&Foo::get, _1), 0, 5, "")); Sebastian Redl

Hi Sebastian, Hmmm...... I think I know what the problem is ... Foo::get is const struct Foo{ std::string get() const { ... } }; So it is not a good candidate to use in string::replace. I wonder how I can work around it, since I want to transform a _copy_ of that. Is there a way to create a copy on the fly? something like: ...bind(rep, std::string(bind(&Foo::get, _1)), 0, 5, "")); Thanks again for your insights. Kobi. On 4/27/06, Sebastian Redl <sebastian.redl@getdesigned.at> wrote:
Kobi Cohen-Arazi wrote:
Hi,
I've tried that, and I got a bunch of errors. I'm using boost::bind for that, not boost::lambda. Here is the error
The following line: std::transform(array.begin(), array.end(), std::back_inserter(tr), bind(&std::string::replace, bind(&Foo::get, _1), 0, 5, ""));
generates: error: no matching function for call to 'bind(<unknown type>, boost::_bi::bind_t<const std::string&, boost::_mfi::cmf0<const std::string&, Foo>, boost::_bi::list1<boost::arg<1> > >, int, uint32_t&, const char [1])'
Hmmm ... the <unknown type> is suspicious. The problem might be that &std::string::replace is ambiguous, as it is overloaded. Try this:
std::string & (std::string::*rep)(std::string::size_type, std::string::size_type, const char *) = &std::string::replace; std::transform(array.begin(), array.end(), std::back_inserter(tr), bind(rep, bind(&Foo::get, _1), 0, 5, ""));
Sebastian Redl _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

OK. Next stage: define a small helper: std::string removeConst (const std::string& s) { return s; } // define a ptr to member func std::string::replace std::string & (std::string::*rep)(std::string::size_type, std::string::size_type, const char *) = &std::string::replace; // try to transform from // but will not work. Compile fails std::transform(array.begin(), array(), std::back_inserter(tr), boost::bind(rep, boost::bind(&removeConst, boost::bind(&Foo::get, _1)), 0, 5, "")); // however that will work, so I probably missing something up there std::transform(array.begin(), array(), std::back_inserter(tr), boost::bind(&removeConst, boost::bind(&Foo::get, _1))); Any idea? Thanks, Kobi. On 4/27/06, Kobi Cohen-Arazi <kobi.cohenarazi@gmail.com> wrote:
Hi Sebastian,
Hmmm...... I think I know what the problem is ... Foo::get is const
struct Foo{ std::string get() const { ... } };
So it is not a good candidate to use in string::replace. I wonder how I can work around it, since I want to transform a _copy_ of that. Is there a way to create a copy on the fly? something like: ...bind(rep, std::string(bind(&Foo::get, _1)), 0, 5, ""));
Thanks again for your insights. Kobi.
On 4/27/06, Sebastian Redl <sebastian.redl@getdesigned.at> wrote:
Kobi Cohen-Arazi wrote:
Hi,
I've tried that, and I got a bunch of errors. I'm using boost::bind for that, not boost::lambda. Here is the error
The following line: std::transform(array.begin(), array.end(), std::back_inserter(tr), bind(&std::string::replace, bind(&Foo::get, _1), 0, 5, ""));
generates: error: no matching function for call to 'bind(<unknown type>, boost::_bi::bind_t<const std::string&, boost::_mfi::cmf0<const std::string&, Foo>, boost::_bi::list1<boost::arg<1> > >, int, uint32_t&, const char [1])'
Hmmm ... the <unknown type> is suspicious. The problem might be that &std::string::replace is ambiguous, as it is overloaded. Try this:
std::string & (std::string::*rep)(std::string::size_type, std::string::size_type, const char *) = &std::string::replace; std::transform(array.begin(), array.end(), std::back_inserter(tr), bind(rep, bind(&Foo::get, _1), 0, 5, ""));
Sebastian Redl _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

Getting much much closer: The following will work: Add that function std::string& replace (std::string s, int pos, int n, const char* c) { return s.replace (pos, n , c); } And use it instead of std::string::replace std::transform( array.begin(), array(), std::back_inserter(tr), boost::bind(replace, boost::bind(&removeConst, boost::bind(&Foo::get, _1)), 0, 5, "")); WORKS !!! HOWEVER, if I'm putting & in replace's std::string argument, I'll get the compile errors (If u need them, just let me know and I'll dump it here). so that minor change (note the std::string&) std::string& replace (std::string& s, int pos, int n, const char* c) { return s.replace (pos, n , c); } Will not work ! Why adding the & hurts? Kobi. On 4/27/06, Kobi Cohen-Arazi <kobi.cohenarazi@gmail.com> wrote:
OK.
Next stage: define a small helper: std::string removeConst (const std::string& s) { return s; }
// define a ptr to member func std::string::replace
std::string & (std::string::*rep)(std::string::size_type, std::string::size_type, const char *) = &std::string::replace;
// try to transform from // but will not work. Compile fails std::transform( array.begin(), array(), std::back_inserter(tr), boost::bind(rep, boost::bind(&removeConst, boost::bind(&Foo::get, _1)), 0, 5, ""));
// however that will work, so I probably missing something up there std::transform(array.begin(), array(), std::back_inserter(tr), boost::bind(&removeConst, boost::bind(&Foo::get, _1)));
Any idea? Thanks, Kobi.
On 4/27/06, Kobi Cohen-Arazi <kobi.cohenarazi@gmail.com> wrote:
Hi Sebastian,
Hmmm...... I think I know what the problem is ... Foo::get is const
struct Foo{ std::string get() const { ... } };
So it is not a good candidate to use in string::replace. I wonder how I can work around it, since I want to transform a _copy_ of that. Is there a way to create a copy on the fly? something like: ...bind(rep, std::string(bind(&Foo::get, _1)), 0, 5, ""));
Thanks again for your insights. Kobi.
On 4/27/06, Sebastian Redl <sebastian.redl@getdesigned.at> wrote:
Kobi Cohen-Arazi wrote:
Hi,
I've tried that, and I got a bunch of errors. I'm using boost::bind for that, not boost::lambda. Here is the error
The following line: std::transform(array.begin(), array.end(), std::back_inserter(tr), bind(&std::string::replace, bind(&Foo::get, _1), 0, 5, ""));
generates: error: no matching function for call to 'bind(<unknown type>, boost::_bi::bind_t<const std::string&, boost::_mfi::cmf0<const std::string&, Foo>, boost::_bi::list1<boost::arg<1> > >, int, uint32_t&, const char [1])'
Hmmm ... the <unknown type> is suspicious. The problem might be that &std::string::replace is ambiguous, as it is overloaded. Try this:
std::string & (std::string::*rep)(std::string::size_type, std::string::size_type, const char *) = &std::string::replace; std::transform(array.begin(), array.end(), std::back_inserter(tr), bind(rep, bind(&Foo::get, _1), 0, 5, ""));
Sebastian Redl _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

Kobi Cohen-Arazi wrote:
Will not work ! Why adding the & hurts? Kobi.
Because you attempt to bind a non-const reference to a temporary object (the return value of get(). The compiler refuses to do that. The compiler doesn't catch another possibly problematic situation, though, and that's replace's return by reference. You're returning a reference to a function parameter, and that's generally not a good idea. On the other hand, the removeConst function does absolutely nothing in your program except create yet another copy of the string. get() already returns a copy. The function is const, but its return value is not a const reference. Sebastian Redl

Hi Sebastian, You are 100% right. The return by reference is wrong. and the removeConst is absolutely not needed. It works just fine without. And I understand why adding & to the std::string is wrong. So just a quick recap, to see if we have 100% of the solution: There is no way to use directly the std::string::replace since get() is const member function. We do need a replace wrapper, which unfortunately creating std::string instances. Am I right here? Thanks for your help! Kobi. On 4/27/06, Sebastian Redl <sebastian.redl@getdesigned.at> wrote:
Kobi Cohen-Arazi wrote:
Will not work ! Why adding the & hurts? Kobi.
Because you attempt to bind a non-const reference to a temporary object (the return value of get(). The compiler refuses to do that. The compiler doesn't catch another possibly problematic situation, though, and that's replace's return by reference. You're returning a reference to a function parameter, and that's generally not a good idea.
On the other hand, the removeConst function does absolutely nothing in your program except create yet another copy of the string. get() already returns a copy. The function is const, but its return value is not a const reference.
Sebastian Redl _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

Kobi Cohen-Arazi wrote:
There is no way to use directly the std::string::replace since get() is const member function.
Um, no, I don't think get's const-ness has anything to do with it. I still think it's an ambiguity problem.
We do need a replace wrapper, which unfortunately creating std::string instances.
Have you tried the member function pointer approach I showed? Sebastian

Just to make sure I wrote it right. My Foo::get is const std::string& Foo::get () cosnt {...} So it is a const func and it returns const &, so I can't see a way that string::replace may alter that string without having any kind of trick (wrapper func etc ...) but tell me what you think about that. Kobi. On 4/27/06, Sebastian Redl <sebastian.redl@getdesigned.at> wrote:
Kobi Cohen-Arazi wrote:
There is no way to use directly the std::string::replace since get() is const member function.
Um, no, I don't think get's const-ness has anything to do with it. I still think it's an ambiguity problem.
We do need a replace wrapper, which unfortunately creating std::string instances.
Have you tried the member function pointer approach I showed?
Sebastian _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

Kobi Cohen-Arazi wrote:
Just to make sure I wrote it right. My Foo::get is
const std::string& Foo::get () cosnt {...}
So it is a const func and it returns const &, so I can't see a way that string::replace may alter that string without having any kind of trick (wrapper func etc ...) but tell me what you think about that.
OK, in that case you're right. Your original posting had get as std::string Foo::get() const; I'll have to consider the other problem, but for today I'm sick of coding. Sebastian

Yes. I've tried the ptr to std::string::replace here what I get after bunch of template errors: /usr/include/boost/bind/mem_fn_template.hpp:339: error: invalid conversion from 'const std::basic_string<char, std::char_traits<char>, std::allocator<char> >*' to 'std::basic_string<char, std::char_traits<char>, std::allocator<char> >*' Kobi. On 4/27/06, Kobi Cohen-Arazi <kobi.cohenarazi@gmail.com> wrote:
Hi Sebastian,
You are 100% right. The return by reference is wrong. and the removeConst is absolutely not needed. It works just fine without. And I understand why adding & to the std::string is wrong.
So just a quick recap, to see if we have 100% of the solution: There is no way to use directly the std::string::replace since get() is const member function. We do need a replace wrapper, which unfortunately creating std::string instances.
Am I right here?
Thanks for your help! Kobi.
On 4/27/06, Sebastian Redl <sebastian.redl@getdesigned.at > wrote:
Kobi Cohen-Arazi wrote:
Will not work ! Why adding the & hurts? Kobi.
Because you attempt to bind a non-const reference to a temporary object (the return value of get(). The compiler refuses to do that. The compiler doesn't catch another possibly problematic situation, though, and that's replace's return by reference. You're returning a reference to a function parameter, and that's generally not a good idea.
On the other hand, the removeConst function does absolutely nothing in your program except create yet another copy of the string. get() already returns a copy. The function is const, but its return value is not a const reference.
Sebastian Redl _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
participants (2)
-
Kobi Cohen-Arazi
-
Sebastian Redl