Thread: boost lambda expression

  1. #1
    Registered User
    Join Date
    Nov 2006
    Posts
    519

    boost lambda expression

    hi,

    can't I call member functions from an placeholder of a boost-like lambda expression?
    look on the example below please:


    Code:
    #include <iostream>
    #include <algorithm>
    #include <iterator>
    #include <vector>
    #include <boost/lambda/lambda.hpp>
    
    using namespace std;
    using namespace boost::lambda;
    
    int main(int argc, char **argv)
    {
    // this works:
    
    	vector<string> v1(10);
    	fill(v1.begin(), v1.end(), "haha");
    	for_each(v1.begin(), v1.end(), cout << _1 << " ");
    cout << endl;
    
    // this works, too:
    
    	vector<string*> v2(10);
    	fill(v2.begin(), v2.end(), new string("hehe"));
    	for_each(v2.begin(), v2.end(), cout << *_1 << " ");
    cout << endl;
    
    // this doesn't:
    
    	vector<string> v3(10);
    	fill(v3.begin(), v3.end(), "hoho");
    	for_each(v3.begin(), v3.end(), cout << _1->c_str() << " ");
            // error: base operand of ‘->’ has non-pointer type ‘const   
            // boost::lambda::lambda_functor<boost::lambda::placeholder<1> >’
    
    	cout << v3.begin()->c_str() << endl;      // this works, just to be sure
    cout << endl;
    Thanks for any idea!
    Last edited by pheres; 04-25-2007 at 02:57 PM.

  2. #2
    semi-colon generator ChaosEngine's Avatar
    Join Date
    Sep 2005
    Location
    Chch, NZ
    Posts
    597
    I don't think lambda can do that. but bind would probably work.
    "I saw a sign that said 'Drink Canada Dry', so I started"
    -- Brendan Behan

    Free Compiler: Visual C++ 2005 Express
    If you program in C++, you need Boost. You should also know how to use the Standard Library (STL). Want to make games? After reading this, I don't like WxWidgets anymore. Want to add some scripting to your App?

  3. #3
    Registered User
    Join Date
    Nov 2006
    Posts
    519
    Quote Originally Posted by ChaosEngine View Post
    I don't think lambda can do that. but bind would probably work.
    Is there any advantage from bind above defining a normal functor?

    and maybe do you know why that doesn't work?
    Code:
    vector<string*> v2(10);
    fill(v2.begin(), v2.end(), new string("hehe"));
    for_each(v2.begin(), v2.end(), cout << *_1 << " ");
    for_each(v2.begin(), v2.end(), delete _1 ); //error
    // error: type ‘const struct boost::lambda::lambda_functor<boost::lambda::placeholder<1>     
    //>’ argument given to ‘delete’, expected pointer
    shouldn't the placeholder _1 become a (string-)pointer as it obviously does in the expression above ( cout << *_1 << " " )?
    Last edited by pheres; 04-25-2007 at 04:11 PM.

  4. #4
    aoeuhtns
    Join Date
    Jul 2005
    Posts
    581
    No. It doesn't. The placeholders are used to create objects with operator() defined. For example, _1 is an object with operator() defined so that it takes one argument and straightly returns that value. It also has operator* defined, though, which creates a function object where operator() takes an argument and dereferences it for its return value.

    If you want full-blooded lambdas, you'll need to use a language that doesn't suck (at functional programming).
    There are 10 types of people in this world, those who cringed when reading the beginning of this sentence and those who salivated to how superior they are for understanding something as simple as binary.

  5. #5
    Registered User
    Join Date
    Nov 2006
    Posts
    519
    I'm not shure if I got it:

    for_each(v2.begin(), v2.end(), cout << *_1 << " ");

    -> _1 is "used to create objects with operator() defined [...] that it takes one argument and straightly returns that value."
    So it takes what? an interator? and returns what? also an interator? what exactly happens in this line?

    I doesn't see the differnce to this one:

    for_each(v2.begin(), v2.end(), delete _1 );

    if *_i in the first line returns a string, than _i is returning a string*. ok that seems perfekt, because delete wants exactly that: an string*.

    on what point is my brain going out of order?

  6. #6
    semi-colon generator ChaosEngine's Avatar
    Join Date
    Sep 2005
    Location
    Chch, NZ
    Posts
    597
    Quote Originally Posted by pheres View Post
    Is there any advantage from bind above defining a normal functor?
    well you don't have to write the functor for a start!
    I'm not shure if I got it:

    for_each(v2.begin(), v2.end(), cout << *_1 << " ");

    -> _1 is "used to create objects with operator() defined [...] that it takes one argument and straightly returns that value."
    So it takes what? an interator? and returns what? also an interator? what exactly happens in this line?

    I doesn't see the differnce to this one:

    for_each(v2.begin(), v2.end(), delete _1 );

    if *_i in the first line returns a string, than _i is returning a string*. ok that seems perfekt, because delete wants exactly that: an string*.

    on what point is my brain going out of order?
    ok first up, damn you for asking this, 'cos now I have to think about it and anything lambda/bind related makes my brain hurt!

    right, think of it like this.
    _1 is not "returning a string*". _1 conceptually looks more like this
    Code:
    template <class something, class fn, class returntype, class arg1> // returntype and arg1 may not be present, depending on the function
    class _1
    {
        // ctor
         _1(something &thing, fn func)
         : mything(thing)
         , myfunc(func)
         {
         }
    
         returntype operator()(arg1 arg)
        {
            return func(mything, arg);
         }
    private:
         something &mything;
         fn myfunc;
    }
    now to say that's a vast oversimplification would be like saying the pacific is a really big lake, but anyway.

    when you do your for_each it actually looks like this
    Code:
    std::list<stuff> slist;
    for-each (slist.begin(), slist.end(), cout << _1);
    
    // pseudo-code
    for (; begin != end; ++begin)
    {
         _1<stuff, ostream(*)(ostream &, const stuff&)> // ostream(*)(ostream &, const stuff&) is a function pointer type
             lambda_obj(begin, &operator<<(ostream &, const stuff&);
    
         lambda_obj();
    }
    so you can see that the code never calls lambda_obj.c_str(). when you do
    Code:
    for_each(v3.begin(), v3.end(), cout << _1->c_str()
    the compiler goes "hmmm class _1 doesn't HAVE a c_str method!"

    the reason that *_1 works is that _1 actually does overload the * operator. If you're really feeling masochistic you can have a look in boost/lambda/detail/operator_lambda_func_base.hpp and after you've waded through the preprocessor madness you'll see it
    "I saw a sign that said 'Drink Canada Dry', so I started"
    -- Brendan Behan

    Free Compiler: Visual C++ 2005 Express
    If you program in C++, you need Boost. You should also know how to use the Standard Library (STL). Want to make games? After reading this, I don't like WxWidgets anymore. Want to add some scripting to your App?

  7. #7
    Registered User
    Join Date
    Nov 2006
    Posts
    519
    Thank you for clearing that up and sorry for hurting you.
    I had the idea I've found a idiom for super easy fast general inline expressions in cyclic algorithms instead of defining delete-that-special-stuff-or-whatever functors hidden somewhere in my code far away from the point they are actually used. seems that I expected to much, hm

  8. #8
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    lambda is limited by language capabilities. You can overload most operators, but not all. delete _1 will not compile because _1 is not a pointer, and it it was, it would do the wrong thing, because the delete operator cannot be overloaded.
    Similarly, foo(_1) will call the function foo passing the placeholder as argument. If foo doesn't accept this, the expression won't compile. Again, the reason is that you cannot overload function calls based on the arguments, just the function object. Therefore, you have to use lambda's binders for function calls:
    Code:
    bind(foo, _1)
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  9. #9
    Registered User
    Join Date
    Nov 2006
    Posts
    519
    ok so generally asked:

    is there a method (especially from boost) to delete all pointers contained in a vector through ONE for_each call WITHOUT the use of some extra defined helper function/functor?

    and if not (that seems to be true): where is the advantage to use boosts lambda expressions?

    Code:
    // without boost lambda:
    
    void delString(string* _s)     // extra work
    {
      delete _s;
    }
    
    void func()
    {
      vector<string*> v2(10);
      fill(v2.begin(), v2.end(), new string("abc"));
      for_each(v2.begin(), v2.end(), delString);
    }
    
    // with boost lambda (equally ugly):
    
    void delString(String* _s)     // extra work
    {
      delete _s;
    }
    
    void func()
    {
      vector<string*> v2(10);
      fill(v2.begin(), v2.end(), new string("abc"));
      for_each(v2.begin(), v2.end(), bind(delString, _1) );
    }
    
    // without extra work, that would be great:
    
    void func()  // is there some way to do it like this?
    {
      vector<string*> v2(10);
      fill(v2.begin(), v2.end(), new string("abc"));
      for_each(v2.begin(), v2.end(), delete _1 );    // or bind( delete, _1 ) or whatever
    }
    Last edited by pheres; 04-26-2007 at 04:50 AM.

  10. #10
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Not really. The only advantage you have is that a delete functor is predefined in lambda.
    Code:
    for_each(v2.begin(), v2.end(), bind(delete_ptr(), _1));
    Of course, you could save yourself the trouble and just store smart pointers like shared_ptr in the container, or use a boost:tr_vector directly.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  11. #11
    Registered User
    Join Date
    Nov 2006
    Posts
    519
    Quote Originally Posted by CornedBee View Post
    Not really. The only advantage you have is that a delete functor is predefined in lambda.
    Code:
    for_each(v2.begin(), v2.end(), bind(delete_ptr(), _1));
    Oh thanks, hadn't found that yet.

    Quote Originally Posted by CornedBee View Post
    Of course, you could save yourself the trouble and just store smart pointers like shared_ptr in the container, or use a boost:tr_vector directly.
    that isn't always meaningful if one need explicit control over the lifetime of some objects. think for example about a container holding various tasks an object shall execute. tasks can be defined, executed, or redefined at any time (so you have to explicitly delete old tasks(i.e. clear the container) and add new ones).
    (it's for a part of a game engine if you wonder what strange stuff people do*g)

    EDIT:
    If I think about it, shared_ptr() equally allows me to free memory it on demand through it's release function. so your suggestion is a proper way to handle the situation.
    c++ and the 1001 ways to do something...
    Last edited by pheres; 04-26-2007 at 07:32 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Help with making a Math Expression DLL
    By MindWorX in forum C Programming
    Replies: 19
    Last Post: 07-19-2007, 11:37 PM
  2. Screwy Linker Error - VC2005
    By Tonto in forum C++ Programming
    Replies: 5
    Last Post: 06-19-2007, 02:39 PM
  3. recursion error
    By cchallenged in forum C Programming
    Replies: 2
    Last Post: 12-18-2006, 09:15 AM
  4. Please Help - Problem with Compilers
    By toonlover in forum C++ Programming
    Replies: 5
    Last Post: 07-23-2005, 10:03 AM
  5. Expression Evaluator Contest
    By Stack Overflow in forum Contests Board
    Replies: 20
    Last Post: 03-29-2005, 10:34 AM