C++0x lambda and capturing computed values

Discussion in 'C++' started by Sohail Somani, May 7, 2009.

  1. Hello,

    I'm pretty sure the answer is "no" but is it possible to capture
    computed values?

    Specifically, I am thinking of the following case:

    vector<function<void()>> functions;

    for(iterator it = ...)
    {
    functions.push_back(boost::bind(whatever,*it););
    }

    Here, the "*it" sub expression passes in a computed value to boost::bind
    which is then stored by value. If I change it to the following:

    for(...)
    {
    functions.push_back([it](){whatever(*it);});
    }

    This is a potential bug since the iterator can become invalidated by the
    time the function is called.

    The undesirable alternative is:

    for(...)
    {
    value_type & t = *it;
    functions.push_back([t](){whatever(t);});
    }

    It would be ideal if I could do something like:

    functions.push-back([t=*it](){whatever(t);});

    Any thoughts or suggestions?

    Thanks in advance!

    --
    Sohail Somani
    http://uint32t.blogspot.com
    Sohail Somani, May 7, 2009
    #1
    1. Advertising

  2. Sohail Somani

    SG Guest

    On 7 Mai, 19:27, Sohail Somani <> wrote:
    >
    > vector<function<void()>> functions;
    >
    > for(iterator it = ...)
    > {
    >   functions.push_back(boost::bind(whatever,*it););
    > }
    >
    > Here, the "*it" sub expression passes in a computed value to boost::bind
    > which is then stored by value. If I change it to the following:
    >
    > for(...)
    > {
    >   functions.push_back([it](){whatever(*it);});
    > }
    >
    > This is a potential bug since the iterator can become invalidated by the
    > time the function is called.
    >
    > The undesirable alternative is:
    >
    > for(...)
    > {
    >   value_type & t = *it;
    >   functions.push_back([t](){whatever(t);});
    > }


    I had to look into the draft again to check whether it actually does
    what you seem to think it does due to decltype(t) being a reference.
    But yes, it captures the referred-to object by value. So, inside the
    lambda's body decltype(t) will not be a reference and it'll be
    equivalent to what your first version with boost::bind does.

    > It would be ideal if I could do something like:
    >
    > functions.push-back([t=*it](){whatever(t);});
    >
    > Any thoughts or suggestions?


    Interesting idea. But it'll hardly save you typing. IMHO,

    auto&& t = *it;
    functions.push_back([=]{whatever(t);});

    is an okay-solution which doesn't justify a more complicated grammar
    in the capture clause.


    Cheers!
    SG
    SG, May 7, 2009
    #2
    1. Advertising

  3. SG wrote:
    > On 7 Mai, 19:27, Sohail Somani <> wrote:
    >> The undesirable alternative is:
    >>
    >> for(...)
    >> {
    >> value_type & t = *it;
    >> functions.push_back([t](){whatever(t);});
    >> }

    >
    > I had to look into the draft again to check whether it actually does
    > what you seem to think it does due to decltype(t) being a reference.
    > But yes, it captures the referred-to object by value. So, inside the
    > lambda's body decltype(t) will not be a reference and it'll be
    > equivalent to what your first version with boost::bind does.


    I had to double-check as well :)

    Just to clarify, your understanding comes from [expr.prim.lambda]/7 ?

    >> It would be ideal if I could do something like:
    >>
    >> functions.push-back([t=*it](){whatever(t);});
    >>
    >> Any thoughts or suggestions?

    >
    > Interesting idea. But it'll hardly save you typing. IMHO,
    >
    > auto&& t = *it;
    > functions.push_back([=]{whatever(t);});
    >
    > is an okay-solution which doesn't justify a more complicated grammar
    > in the capture clause.


    Well the actual case is something like:

    for(iterator it1, it2, it3 ...)
    {
    .. some stuff here ..
    functions.push_back(bind(whatever,*it1,*it2,*it3));
    }

    To me, the alternative is quite verbose.

    For comparison:

    for(iterator it1, it2, it3 ...)
    {
    auto&& t1=*it1;
    auto&& t2=*it2;
    auto&& t3=*it3;
    functions.push_back([=](){whatever(t);});
    }

    or

    for(iterator it1, it2, it3 ...)
    {
    functions.push_back([t1=*it1,t2=*it2,t3=*it3]()
    {whatever(t1,t2,t3);});
    }

    Less typing even if it is for 6*3 characters is better if you ask me.
    Seems that bind is not obsoleted by lambda (I didn't expect it to be
    anyway.)

    --
    Sohail Somani
    http://uint32t.blogspot.com
    Sohail Somani, May 7, 2009
    #3
  4. Sohail Somani wrote:
    > for(iterator it1, it2, it3 ...)
    > {
    > functions.push_back([t1=*it1,t2=*it2,t3=*it3]()
    > {whatever(t1,t2,t3);});
    > }
    >
    > Less typing even if it is for 6*3 characters is better if you ask me.
    > Seems that bind is not obsoleted by lambda (I didn't expect it to be
    > anyway.)


    What about something like:

    for(...)
    {
    functions.push_back([](){whatever(<*it1>,<*it2>,<*it3>);}
    }

    I dunno... Just something to avoid all the typing would be nice. I'm
    sure it's not gonna happen but this is from the result of porting an app
    to use C++0x lambda where possible.

    --
    Sohail Somani
    http://uint32t.blogspot.com
    Sohail Somani, May 7, 2009
    #4
  5. Sohail Somani

    SG Guest

    On 7 Mai, 21:34, Sohail Somani <> wrote:
    > SG wrote:
    > > I had to look into the draft again to check whether it actually does
    > > what you seem to think it does [...]

    >
    > I had to double-check as well :)
    > Just to clarify, your understanding comes from [expr.prim.lambda]/7 ?


    In N2857.pdf it's §5.2.1/8 [expr.prim.lambda] where it says that the
    "object type" in case of a reference is the type the reference refers
    to.

    > [...]
    > for(iterator it1, it2, it3 ...)
    > {
    >   functions.push_back([t1=*it1,t2=*it2,t3=*it3]()
    >                       {whatever(t1,t2,t3);});
    > }


    You could use std::bind here. Nobody forces you to use lambdas. :)

    functions.push_back(std::bind(whatever,*it1,*it2,*it3));


    Cheers!
    SG
    SG, May 7, 2009
    #5
  6. SG wrote:
    > On 7 Mai, 21:34, Sohail Somani <> wrote:
    >> SG wrote:
    >>> I had to look into the draft again to check whether it actually does
    >>> what you seem to think it does [...]

    >> I had to double-check as well :)
    >> Just to clarify, your understanding comes from [expr.prim.lambda]/7 ?

    >
    > In N2857.pdf it's §5.2.1/8 [expr.prim.lambda] where it says that the
    > "object type" in case of a reference is the type the reference refers
    > to.
    >
    >> [...]
    >> for(iterator it1, it2, it3 ...)
    >> {
    >> functions.push_back([t1=*it1,t2=*it2,t3=*it3]()
    >> {whatever(t1,t2,t3);});
    >> }

    >
    > You could use std::bind here. Nobody forces you to use lambdas. :)
    >
    > functions.push_back(std::bind(whatever,*it1,*it2,*it3));


    I thought you had to use lambda?!!! Just kidding :)

    Of course, you are right. However, once you have more than one function
    call involved, you can't use bind:

    functions.push_back([<something to keep *itN>](){
    whatever(*it1,*it2,*it3);
    something_else(*it1,*it2,*it3);
    });

    Here is another example:

    bind(&Session::connect,config.server(),config.username(),config.password());

    The equivalent in C++0x lambda is too noisy to use. I cannot hold config
    by reference because of (unlikely but possible) thread-safety issues.

    Anyway, I just wanted to be sure that bind is still useful and you
    shouldn't feel bad for using it :)

    --
    Sohail Somani
    http://uint32t.blogspot.com
    Sohail Somani, May 7, 2009
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Roman Suzi
    Replies:
    13
    Views:
    589
    Bengt Richter
    Jan 7, 2005
  2. Replies:
    2
    Views:
    402
  3. James Kuyper

    Computed values don't tie up

    James Kuyper, Apr 3, 2012, in forum: C Programming
    Replies:
    13
    Views:
    480
    Ben Bacarisse
    Apr 4, 2012
  4. Juha Nieminen
    Replies:
    1
    Views:
    430
    Juha Nieminen
    Apr 22, 2012
  5. Juha Nieminen
    Replies:
    6
    Views:
    587
Loading...

Share This Page