[boost] [scope_exit] can MSVC lambdas capture data members?

classic Classic list List threaded Threaded
16 messages Options
Reply | Threaded
Open this post in threaded view
|

[boost] [scope_exit] can MSVC lambdas capture data members?

lcaminiti
Hello all,

Can anyone try the following code on a MSVC compiler with lambdas (MSVC10?)?

#include <vector>

struct person {};

struct world {
    void add_person(person const& a_person) {
        bool commit = false;
        persons_.push_back(a_person);

        auto scope_exit = [&commit, &persons_]() mutable -> void {
            if(!commit) persons_.pop_back();
        };

        commit = true;
        scope_exit();
    }

private:
    std::vector<person> persons_;
};

int main() {
    world w;
    person p;
    w.add_person(p);
    return 0;
}

This code compiles on GCC 4.5.3 with C++0x extensions (including lambdas) but based on some errors I'm seeing in trunk's ScopeExit regressions tests, I'm guessing it will fail using MSVC lambdas with errors similar to the followings:

error C3480: 'world::persons_': a lambda capture variable must be from an enclosing function scope
warning C4573: the usage of 'world::persons_' requires the compiler to capture 'this' but the current default capture mode does not allow it

Unfortunately, I don't have a MSVC compiler with lambdas so thank you very much for trying my code!
--Lorenzo
Reply | Threaded
Open this post in threaded view
|

Re: [scope_exit] can MSVC lambdas capture data members?

Nathan Ridge

GCC 4.5 is in error to allow that. 4.7 does not allow it.

The correct way to use a data member in the lambda is to capture "this", and then
access the member via "this->member" inside the lambda.

Regards,
Nate
     

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [scope_exit] can MSVC lambdas capture data members?

lcaminiti
Nathan Ridge wrote
GCC 4.5 is in error to allow that. 4.7 does not allow it.

The correct way to use a data member in the lambda is to capture "this", and then
access the member via "this->member" inside the lambda.
OK, thanks. This is a problem for implementing ScopeExit using lambdas on C++11 because the following code:

struct world {
    void add_person(person const& a_person) {
        bool commit = false;
        persons_.push_back(a_person);

        SCOPE_EXIT( (&commit) (&persons_) ) {
            if(!commit) persons_.pop_back();
        }

        commit = true;
    }

private:
    std::vector<person> persons_;
};

Works with the current implementation of ScopeExit that does not use lambdas but it will no longer compile with the implementation of ScopeExit that uses lambdas. Therefore, the lambda implementation of ScopeExit cannot be backward compatible... I will discuss this issue with ScopeExit's main author Alexander Nasonov but this might mean that ScopeExit will never be implemented internally using lambdas, not even on C++11 compilers.

Thanks.
--Lorenzo
Reply | Threaded
Open this post in threaded view
|

Re: [scope_exit] can MSVC lambdas capture data members?

Dave Abrahams
In reply to this post by Nathan Ridge

on Wed Mar 14 2012, Nathan Ridge <zeratul976-AT-hotmail.com> wrote:

> GCC 4.5 is in error to allow that. 4.7 does not allow it.
>
> The correct way to use a data member in the lambda is to capture "this", and then
> access the member via "this->member" inside the lambda.

Actually you get implicit access to all the members once you capture
"this."  That said, I don't think anyone should use that capability :-)

--
Dave Abrahams
BoostPro Computing
http://www.boostpro.com


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [scope_exit] can MSVC lambdas capture data members?

Alexander Nasonov
In reply to this post by lcaminiti
lcaminiti wrote:
>
> Nathan Ridge wrote
> >
> > GCC 4.5 is in error to allow that. 4.7 does not allow it.
> >
> > The correct way to use a data member in the lambda is to capture "this",
> > and then
> > access the member via "this->member" inside the lambda.
> >

If the above it true ...

> Works with the current implementation of ScopeExit that does not use lambdas
> but it will no longer compile with the implementation of ScopeExit that uses
> lambdas. Therefore, the lambda implementation of ScopeExit cannot be
> backward compatible... I will discuss this issue with ScopeExit's main
> author Alexander Nasonov but this might mean that ScopeExit will never be
> implemented internally using lambdas, not even on C++11 compilers.

then don't claim backward-compatibility and make sure that lambda
implementation can't be implicitly enabled (only if a user defines
BOOST_SCOPE_EXIT_USE_LAMBDAS or something like this).

Alex

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [scope_exit] can MSVC lambdas capture data members?

lcaminiti
Alexander Nasonov wrote
lcaminiti wrote:
>
> Nathan Ridge wrote
> >
> > GCC 4.5 is in error to allow that. 4.7 does not allow it.
> >
> > The correct way to use a data member in the lambda is to capture "this",
> > and then
> > access the member via "this->member" inside the lambda.
> >

If the above it true ...

> Works with the current implementation of ScopeExit that does not use lambdas
> but it will no longer compile with the implementation of ScopeExit that uses
> lambdas. Therefore, the lambda implementation of ScopeExit cannot be
> backward compatible... I will discuss this issue with ScopeExit's main
> author Alexander Nasonov but this might mean that ScopeExit will never be
> implemented internally using lambdas, not even on C++11 compilers.

then don't claim backward-compatibility and make sure that lambda
implementation can't be implicitly enabled (only if a user defines
BOOST_SCOPE_EXIT_USE_LAMBDAS or something like this).
1) I'd propose to never implement BOOST_SCOPE_EXIT using lambdas. There is no advantage for the user in the lambda implementation because I already extended BOOST_SCOPE_EXIT to use variadic macros, capture the object `this_`, and capture no variable (using `void`) all of which without using C++11 and maintaining backward compatibility with the existing BOOST_SCOPE_EXIT syntax.

// On all compilers (it never uses C++11 lambdas).
BOOST_SCOPE_EXIT(&commit, &persons_) {
    if(!commit) persons_.pop_back();
} BOOST_SCOPE_EXIT_END

2) However, I'd leave BOOST_SCOPE_EXIT_ALL because it allows for implicit captures using `&` and `=`. This macro uses C++11 lambdas and it is #defined only for C++11 compilers. BOOST_SCOPE_EXIT_ALL and BOOST_SCOPE_EXIT will therefore have different capture semantics (e.g., BOOST_SCOPE_EXIT_ALL cannot capture data members without capturing `this` while BOOST_SCOPE_EXIT can) but if users find that confusing they just don't use SCOPE_EXIT_ALL.

// Only on C++11 compilers (same capture semantics of C++11 lambda and therefore different from BOOST_SCOPE_EXIT).
BOOST_SCOPE_EXIT_ALL(&, this) {
    if(!commit) persons_.pop_back();
}; // Use `;` instead of BOOST_SCOPE_EXIT_END

3) Finally, if you #define BOOST_SCOPE_EXIT_CONFIG_NO_CXX11 (or shall this be NO_CPP11? ;) ) then BOOST_SCOPE_EXIT_ALL is never defined not even on C++11 compilers.

This way the user is always in control and he/she gets the extra benefits of implicit lambda captures when they apply. What do you think?

Thanks.
--Lorenzo
Reply | Threaded
Open this post in threaded view
|

Re: [scope_exit] can MSVC lambdas capture data members?

Alexander Nasonov
lcaminiti wrote:
> 1) I'd propose to never implement BOOST_SCOPE_EXIT using lambdas. There is
> no advantage for the user in the lambda implementation because I already
> extended BOOST_SCOPE_EXIT to use variadic macros, capture the object
> `this_`, and capture no variable (using `void`) all of which without using
> C++11 and maintaining backward compatibility with the existing
> BOOST_SCOPE_EXIT syntax.

If we assume that the new standard is immutable, then you reasoning
makes perfect sense. However, what if it was an oversight by the
standard committee? 'this' is not a local variable, after all. If they
allowed a special case for this, they could also allow data members.

Alex

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [scope_exit] can MSVC lambdas capture data members?

Mathias Gaunard-2
In reply to this post by lcaminiti
On 15/03/12 20:21, lcaminiti wrote:

> 1) I'd propose to never implement BOOST_SCOPE_EXIT using lambdas. There is
> no advantage for the user in the lambda implementation

What about
1) compile-time speed
2) run-time efficiency

Aren't both of those better with lambdas?


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [scope_exit] can MSVC lambdas capture data members?

Mathias Gaunard-2
In reply to this post by Alexander Nasonov
On 16/03/12 03:42, Alexander Nasonov wrote:

> If we assume that the new standard is immutable, then you reasoning
> makes perfect sense. However, what if it was an oversight by the
> standard committee? 'this' is not a local variable, after all. If they
> allowed a special case for this, they could also allow data members.

It is not an oversight, and is this way on purpose.


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [scope_exit] can MSVC lambdas capture data members?

Dave Abrahams

on Fri Mar 16 2012, Mathias Gaunard <mathias.gaunard-AT-ens-lyon.org> wrote:

> On 16/03/12 03:42, Alexander Nasonov wrote:
>
>> If we assume that the new standard is immutable, then you reasoning
>> makes perfect sense. However, what if it was an oversight by the
>> standard committee? 'this' is not a local variable, after all. If they
>> allowed a special case for this, they could also allow data members.
>
> It is not an oversight, and is this way on purpose.

That may be, but it is considered a mistake by at least a few of us on
the commitee, and we've discussed ways to rectify it.

--
Dave Abrahams
BoostPro Computing
http://www.boostpro.com


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [scope_exit] can MSVC lambdas capture data members?

lcaminiti
In reply to this post by Mathias Gaunard-2
Mathias Gaunard-2 wrote
On 15/03/12 20:21, lcaminiti wrote:

> 1) I'd propose to never implement BOOST_SCOPE_EXIT using lambdas. There is
> no advantage for the user in the lambda implementation

What about
1) compile-time speed
2) run-time efficiency

Aren't both of those better with lambdas?
Bases on my LocalFunction benchmarking:
https://svn.boost.org/svn/boost/trunk/libs/local_function/doc/html/boost_localfunction/Alternatives.html

I'd expect ScopeExit with lambdas to be only marginally if at all faster than ScopeExit without lambas for both compile and run time. But I must confess that I didn't directly benchmark ScopeExit with and without lambdas so I could be mistaken.

--Lorenzo
Reply | Threaded
Open this post in threaded view
|

Re: [scope_exit] can MSVC lambdas capture data members?

lcaminiti
In reply to this post by Dave Abrahams
Dave Abrahams wrote
on Fri Mar 16 2012, Mathias Gaunard <mathias.gaunard-AT-ens-lyon.org> wrote:

> On 16/03/12 03:42, Alexander Nasonov wrote:
>
>> If we assume that the new standard is immutable, then you reasoning
>> makes perfect sense. However, what if it was an oversight by the
>> standard committee? 'this' is not a local variable, after all. If they
>> allowed a special case for this, they could also allow data members.
>
> It is not an oversight, and is this way on purpose.
Does anyone know what was the rationale of the committee for this?

That may be, but it is considered a mistake by at least a few of us on
the commitee, and we've discussed ways to rectify it.
Then, as Alex suggested, I will leave the BOOST_SCOPE_EXIT implementation that uses lambdas however it will be disabled by default, enabled only if users explicitly #define BOOST_SCOPE_EXIT_CONFIG_USE_CXX11_LAMBDAS, and I will document that BOOST_SCOPE_EXIT with lambdas is not backward compatible (unless C++11 is rectified to allow lambdas to capture data members).

Thanks a lot.
--Lorenzo
Reply | Threaded
Open this post in threaded view
|

Re: [scope_exit] can MSVC lambdas capture data members?

Mathias Gaunard-2
In reply to this post by lcaminiti
On 16/03/12 20:50, lcaminiti wrote:

>
> Mathias Gaunard-2 wrote
>>
>> On 15/03/12 20:21, lcaminiti wrote:
>>
>>> 1) I'd propose to never implement BOOST_SCOPE_EXIT using lambdas. There
>>> is
>>> no advantage for the user in the lambda implementation
>>
>> What about
>> 1) compile-time speed
>> 2) run-time efficiency
>>
>> Aren't both of those better with lambdas?
>>
>
> Bases on my LocalFunction benchmarking:
> https://svn.boost.org/svn/boost/trunk/libs/local_function/doc/html/boost_localfunction/Alternatives.html
>
> I'd expect ScopeExit with lambdas to be only marginally if at all faster
> than ScopeExit without lambas for both compile and run time. But I must
> confess that I didn't directly benchmark ScopeExit with and without lambdas
> so I could be mistaken.

Doesn't the use of C++11 remove all the ugly virtual stuff?


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [scope_exit] can MSVC lambdas capture data members?

Mathias Gaunard-2
In reply to this post by lcaminiti
On 16/03/12 20:55, lcaminiti wrote:

> Then, as Alex suggested, I will leave the BOOST_SCOPE_EXIT implementation
> that uses lambdas however it will be disabled by default, enabled only if
> users explicitly #define BOOST_SCOPE_EXIT_CONFIG_USE_CXX11_LAMBDAS, and I
> will document that BOOST_SCOPE_EXIT with lambdas is not backward compatible
> (unless C++11 is rectified to allow lambdas to capture data members).

Or you could change your library to explicitly require to bind member
variables or this, like C++11 does.


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [scope_exit] can MSVC lambdas capture data members?

lcaminiti
In reply to this post by Mathias Gaunard-2
Mathias Gaunard-2 wrote
On 16/03/12 20:50, lcaminiti wrote:
>
> Mathias Gaunard-2 wrote
>>
>> On 15/03/12 20:21, lcaminiti wrote:
>>
>>> 1) I'd propose to never implement BOOST_SCOPE_EXIT using lambdas. There
>>> is
>>> no advantage for the user in the lambda implementation
>>
>> What about
>> 1) compile-time speed
>> 2) run-time efficiency
>>
>> Aren't both of those better with lambdas?
>>
>
> Bases on my LocalFunction benchmarking:
> https://svn.boost.org/svn/boost/trunk/libs/local_function/doc/html/boost_localfunction/Alternatives.html
>
> I'd expect ScopeExit with lambdas to be only marginally if at all faster
> than ScopeExit without lambas for both compile and run time. But I must
> confess that I didn't directly benchmark ScopeExit with and without lambdas
> so I could be mistaken.

Doesn't the use of C++11 remove all the ugly virtual stuff?
No, the "virtual stuff" is used by LocalFuncttion* to pass local classes as template parameters but it is not required at all by ScopeExit.

(*) Note: A static member function and a static_cast were used at the end instead of the "virtual stuff" because faster. On C++11, neither of this trick is needed because local classes can be passed as template parameters but not because of lambdas which are not used by LocalFunction.

Thanks,
--Lorenzo
Reply | Threaded
Open this post in threaded view
|

Re: [scope_exit] can MSVC lambdas capture data members?

lcaminiti
In reply to this post by Mathias Gaunard-2
Mathias Gaunard-2 wrote
On 16/03/12 20:55, lcaminiti wrote:

> Then, as Alex suggested, I will leave the BOOST_SCOPE_EXIT implementation
> that uses lambdas however it will be disabled by default, enabled only if
> users explicitly #define BOOST_SCOPE_EXIT_CONFIG_USE_CXX11_LAMBDAS, and I
> will document that BOOST_SCOPE_EXIT with lambdas is not backward compatible
> (unless C++11 is rectified to allow lambdas to capture data members).

Or you could change your library to explicitly require to bind member
variables or this, like C++11 does.
But if I require ScopeExit to explicitly bind member variables or this like C++11 lambdas do, that breaks backward compatibility with code that use the current implementation of ScopeExit :( For example the following code that compiles with the current version of ScopeExit will no longer compile:

struct x {
    int y;
    void f() {
        BOOST_SCOPE_EXIT( (&y) ) {
            y = -1;
        } BOOST_SCOPE_EXIT_END
    }
};

--Lorenzo