empty lambda capture and static

Discussion in 'C++' started by Werner, Aug 2, 2012.

  1. Werner

    Werner Guest

    Hi All,

    I've got this little example compiling under GCC, but I'm
    not sure it is compliant:

    void foo()
    {
    static const double cCOEFFICIENT = 0.1;

    auto x1 = []
    {
    return cCOEFFICIENT*10;
    };
    auto x2 = []
    {
    return cCOEFFICIENT*2;
    };
    }
    The question is:

    Where in the standard does it state that the static
    constant defined at enclosing function scoped [is]
    visible in the lambda when using an empty capture?

    Kind regards,

    Werner
    Werner, Aug 2, 2012
    #1
    1. Advertising

  2. On 8/2/2012 7:46 AM, Werner wrote:
    > I've got this little example compiling under GCC, but I'm
    > not sure it is compliant:
    >
    > void foo()
    > {
    > static const double cCOEFFICIENT = 0.1;
    >
    > auto x1 = []
    > {
    > return cCOEFFICIENT*10;
    > };
    > auto x2 = []
    > {
    > return cCOEFFICIENT*2;
    > };
    > }
    > The question is:
    >
    > Where in the standard does it state that the static
    > constant defined at enclosing function scoped [is]
    > visible in the lambda when using an empty capture?


    The emptiness means that everything is captured by value. See
    [expr.prim.lambda]/14. I think that's what you're asking.

    V
    --
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Aug 2, 2012
    #2
    1. Advertising

  3. Victor Bazarov <> wrote:
    > The emptiness means that everything is captured by value. See
    > [expr.prim.lambda]/14. I think that's what you're asking.


    What? I tought that "[=]" was used to capture everything by value.
    Juha Nieminen, Aug 2, 2012
    #3
  4. On 8/2/2012 9:22 AM, Juha Nieminen wrote:
    > Victor Bazarov <> wrote:
    >> The emptiness means that everything is captured by value. See
    >> [expr.prim.lambda]/14. I think that's what you're asking.

    >
    > What? I tought that "[=]" was used to capture everything by value.


    Sorry, you're right. Misread the Standard. Unless captured by copy,
    any implicitly captured entity is captured by reference.

    V
    --
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Aug 2, 2012
    #4
  5. Werner

    Werner Guest

    On Thursday, August 2, 2012 2:12:06 PM UTC+2, Victor Bazarov wrote:

    > The emptiness means that everything is captured by value. See
    >
    > [expr.prim.lambda]/14. I think that's what you're asking.


    I'm asking what "[]" captures.

    At I understand [/14], it describes when a copy (or by value)
    is captured.

    From the text I understand that this is the case when a
    "[=]" capture is specified ("capture default is ="), or
    if an explicit capture exists not including &:

    int a, b;
    [a, &b] iow a is a copy, b is a reference.

    .... but what would a, b be when an empty capture
    is specified, and should it be visible in the scope
    of the lambda?

    []
    {
    a ?
    b ?
    }

    Kind regards,

    Werner
    Werner, Aug 2, 2012
    #5
  6. On 8/2/2012 9:51 AM, Werner wrote:
    > On Thursday, August 2, 2012 2:12:06 PM UTC+2, Victor Bazarov wrote:
    >
    >> The emptiness means that everything is captured by value. See
    >>
    >> [expr.prim.lambda]/14. I think that's what you're asking.

    >
    > I'm asking what "[]" captures.
    >
    > At I understand [/14], it describes when a copy (or by value)
    > is captured.
    >
    > From the text I understand that this is the case when a
    > "[=]" capture is specified ("capture default is ="), or
    > if an explicit capture exists not including &:
    >
    > int a, b;
    > [a, &b] iow a is a copy, b is a reference.
    >
    > ... but what would a, b be when an empty capture
    > is specified, and should it be visible in the scope
    > of the lambda?
    >
    > []
    > {
    > a ?
    > b ?
    > }


    Yes, if no capture is specified, the paragraph 15 is the one you want, I
    think. I misread the /14 to mean that implicit capture is always by
    copy, sorry.

    V
    --
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Aug 2, 2012
    #6
  7. Werner

    Noah Roberts Guest

    On Thursday, August 2, 2012 6:39:16 AM UTC-7, Victor Bazarov wrote:
    > On 8/2/2012 9:22 AM, Juha Nieminen wrote:
    >
    > > Victor Bazarov <> wrote:

    >
    > >> The emptiness means that everything is captured by value. See

    >
    > >> [expr.prim.lambda]/14. I think that's what you're asking.

    >
    > >

    >
    > > What? I tought that "[=]" was used to capture everything by value.

    >
    > Sorry, you're right. Misread the Standard. Unless captured by copy,
    >
    > any implicitly captured entity is captured by reference.


    I believe you were actually correct the first time but not this one. The exception appears to be 'this', which must be captured explicitly or a default must be explicitly supplied. There are good reasons not to do so by using '[=]':

    http://crazycpp.wordpress.com/2011/04/06/lambda-capture-and-object-lifetime/
    Noah Roberts, Aug 6, 2012
    #7
  8. On 8/6/2012 5:56 PM, Noah Roberts wrote:
    > On Thursday, August 2, 2012 6:39:16 AM UTC-7, Victor Bazarov wrote:
    >> On 8/2/2012 9:22 AM, Juha Nieminen wrote:
    >>
    >>> Victor Bazarov <> wrote:

    >>
    >>>> The emptiness means that everything is captured by value. See

    >>
    >>>> [expr.prim.lambda]/14. I think that's what you're asking.

    >>
    >>>

    >>
    >>> What? I tought that "[=]" was used to capture everything by value.

    >>
    >> Sorry, you're right. Misread the Standard. Unless captured by copy,
    >>
    >> any implicitly captured entity is captured by reference.

    >
    > I believe you were actually correct the first time but not this one.
    > The exception appears to be 'this', which must be captured explicitly or
    > a default must be explicitly supplied. There are good reasons not to do
    > so by using '[=]':


    Yes, that portion is kind of confusing. Here are the relevant quotes
    from the Standard:

    [expr.prim.lambda]/15:
    <<An entity is captured by reference if it is implicitly or explicitly
    captured but not captured by copy.>>

    and

    [expr.prim.lambda]/14:
    <<An entity is captured by copy if it is implicitly captured and the
    capture-default is = or if it is explicitly
    captured with a capture that does not include an &.>>

    What I understand from those two sentences is that if you need to
    capture by copy, you have to either say '[=]' (which means everything is
    captured by copy - capture default), or put the name of the captured
    variable without the '&' in front of it, like '[a]'.

    Now, my experimentation shows that unless any capture mode is specified,
    nothing is actually captured. Is that what you're saying?

    Should the following compile? And if so, what is the expected output?
    Will 'a' be captured by reference in 'byref' closure?

    #include <iostream>
    int main()
    {
    int a = 42;
    auto byref = []() { std::cout << "R:" << &a << a << '\n'; };
    auto bycopy = [=]() { std::cout << "C:" << &a << a << '\n'; };
    auto boo = [&a]() { a = 42; };
    std::cout << " :" << &a << a << "\n";
    byref(); bycopy(); boo(); byref(); bycopy();
    }

    Or should 'a' not be captured at all? Comeau online chokes on lambdas
    altogether. VC++ 2010 refuses to compile the 'byref' initialization
    (complaining about 'a' capture), unless I write [&], in which case
    everything works what's expected.

    So, again, are you saying that empty capture clause doesn't actually
    capture anything?

    >
    > http://crazycpp.wordpress.com/2011/04/06/lambda-capture-and-object-lifetime/
    >


    I didn't find that article relevant to the original question, sorry.

    V
    --
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Aug 7, 2012
    #8
  9. On 8/7/2012 8:19 AM, Victor Bazarov wrote:
    > On 8/6/2012 5:56 PM, Noah Roberts wrote:
    >> On Thursday, August 2, 2012 6:39:16 AM UTC-7, Victor Bazarov wrote:
    >>> On 8/2/2012 9:22 AM, Juha Nieminen wrote:
    >>>
    >>>> Victor Bazarov <> wrote:
    >>>
    >>>>> The emptiness means that everything is captured by value. See
    >>>
    >>>>> [expr.prim.lambda]/14. I think that's what you're asking.
    >>>
    >>>>
    >>>
    >>>> What? I tought that "[=]" was used to capture everything by value.
    >>>
    >>> Sorry, you're right. Misread the Standard. Unless captured by copy,
    >>>
    >>> any implicitly captured entity is captured by reference.

    >>
    >> I believe you were actually correct the first time but not this one.
    >> The exception appears to be 'this', which must be captured explicitly or
    >> a default must be explicitly supplied. There are good reasons not to do
    >> so by using '[=]':

    >
    > Yes, that portion is kind of confusing. Here are the relevant quotes
    > from the Standard:
    >
    > [expr.prim.lambda]/15:
    > <<An entity is captured by reference if it is implicitly or explicitly
    > captured but not captured by copy.>>
    >
    > and
    >
    > [expr.prim.lambda]/14:
    > <<An entity is captured by copy if it is implicitly captured and the
    > capture-default is = or if it is explicitly
    > captured with a capture that does not include an &.>>
    >
    > What I understand from those two sentences is that if you need to
    > capture by copy, you have to either say '[=]' (which means everything is
    > captured by copy - capture default), or put the name of the captured
    > variable without the '&' in front of it, like '[a]'.
    >
    > Now, my experimentation shows that unless any capture mode is specified,
    > nothing is actually captured. Is that what you're saying?
    >
    > Should the following compile? And if so, what is the expected output?
    > Will 'a' be captured by reference in 'byref' closure?
    >
    > #include <iostream>
    > int main()
    > {
    > int a = 42;
    > auto byref = []() { std::cout << "R:" << &a << a << '\n'; };
    > auto bycopy = [=]() { std::cout << "C:" << &a << a << '\n'; };
    > auto boo = [&a]() { a = 42; };
    > std::cout << " :" << &a << a << "\n";
    > byref(); bycopy(); boo(); byref(); bycopy();
    > }
    >
    > Or should 'a' not be captured at all? Comeau online chokes on lambdas
    > altogether. VC++ 2010 refuses to compile the 'byref' initialization
    > (complaining about 'a' capture), unless I write [&], in which case
    > everything works what's expected.


    Oh, and if I change the declaration of 'a' to

    static int a = 42;

    then it becomes accessible in every closure without the need to capture,
    and actually VC++ complains that it can't capture 'a' by ref in the
    'boo' closure. The code that compiles is:

    #include <iostream>
    int main()
    {
    int a = 42;
    auto byref = [&]() { std::cout << "R:" << &a << a << '\n'; };
    auto bycopy = [=]() { std::cout << "C:" << &a << a << '\n'; };
    auto boo = [&a]() { a = 42; };
    std::cout << " :" << &a << a << "\n";
    byref(); bycopy(); boo(); byref(); bycopy();
    }

    and the output from 'byref' and 'bycopy' is the same (compared to the
    other sample where the addresses are different based on the capture).

    >
    > So, again, are you saying that empty capture clause doesn't actually
    > capture anything?
    >
    >>
    >> http://crazycpp.wordpress.com/2011/04/06/lambda-capture-and-object-lifetime/
    >>
    >>

    >
    > I didn't find that article relevant to the original question, sorry.
    >
    > V


    V
    --
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Aug 7, 2012
    #9
  10. Werner

    Casey Guest

    On Tuesday, August 7, 2012 7:19:23 AM UTC-5, Victor Bazarov wrote:
    > So, again, are you saying that empty capture clause doesn't actually
    > capture anything?


    The capture rules are spelled out in 5.1.2/10-12: an entity is explicitly captured if it appears in the capture list, implicitly captured if a capture-default is specified. An entity is captured if it is explicitly or implicitly captured.

    Consequently, an empty lambda-introducer "[]" captures nothing.
    Casey, Aug 7, 2012
    #10
  11. On 8/7/2012 10:45 AM, Casey wrote:
    > On Tuesday, August 7, 2012 7:19:23 AM UTC-5, Victor Bazarov wrote:
    >> So, again, are you saying that empty capture clause doesn't actually
    >> capture anything?

    >
    > The capture rules are spelled out in 5.1.2/10-12: an entity is explicitly captured if it appears in the capture list, implicitly captured if a capture-default is specified. An entity is captured if it is explicitly or implicitly captured.
    >
    > Consequently, an empty lambda-introducer "[]" captures nothing.


    Which then leads to the conclusion that a static object is not really
    "captured". It's accessible since it's in the scope and that's all it
    is. Right?

    V
    --
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Aug 7, 2012
    #11
  12. Werner

    Casey Carter Guest

    On 2012-08-07 10:29, Victor Bazarov wrote:
    > Which then leads to the conclusion that a static object is not really
    > "captured". It's accessible since it's in the scope and that's all it
    > is. Right?


    Yes, capture only applies to *this* and "variables with automatic
    storage duration declared in the reaching scope of the local lambda
    expression" (5.1.2/10-11).
    Casey Carter, Aug 7, 2012
    #12
  13. Werner

    Casey Carter Guest

    On 2012-08-02 06:46, Werner wrote:
    > Hi All,
    >
    > I've got this little example compiling under GCC, but I'm
    > not sure it is compliant:
    >
    > void foo()
    > {
    > static const double cCOEFFICIENT = 0.1;
    >
    > auto x1 = []
    > {
    > return cCOEFFICIENT*10;
    > };
    > auto x2 = []
    > {
    > return cCOEFFICIENT*2;
    > };
    > }
    > The question is:
    >
    > Where in the standard does it state that the static
    > constant defined at enclosing function scoped [is]
    > visible in the lambda when using an empty capture?
    >
    > Kind regards,
    >
    > Werner


    The rules for lambda capture only apply to *this* and to variables with
    automatic storage duration; names for other kinds of entities aren't
    treated specially. That static is visible for the same reason it would
    be if you wrote:

    void foo()
    {
    static const double cCOEFFICIENT = 0.1;

    {
    return cCOEFFICIENT*10;
    }
    {
    return cCOEFFICIENT*2;
    }
    }
    Casey Carter, Aug 7, 2012
    #13
    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. Max
    Replies:
    7
    Views:
    9,087
  2. Roman Suzi
    Replies:
    13
    Views:
    595
    Bengt Richter
    Jan 7, 2005
  3. Steve Dogers

    lambda vs non-lambda proc

    Steve Dogers, Mar 30, 2009, in forum: Ruby
    Replies:
    1
    Views:
    161
    Sean O'Halpin
    Mar 30, 2009
  4. SG
    Replies:
    1
    Views:
    325
    mmehlich
    Nov 20, 2012
  5. Haochen Xie
    Replies:
    4
    Views:
    234
    Haochen Xie
    Mar 17, 2013
Loading...

Share This Page