[scope_exit] can MSVC lambdas capture data members?

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 -- View this message in context: http://boost.2283326.n4.nabble.com/boost-scope-exit-can-MSVC-lambdas-capture... Sent from the Boost - Dev mailing list archive at Nabble.com.

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

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 -- View this message in context: http://boost.2283326.n4.nabble.com/boost-scope-exit-can-MSVC-lambdas-capture... Sent from the Boost - Dev mailing list archive at Nabble.com.

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

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 -- View this message in context: http://boost.2283326.n4.nabble.com/boost-scope-exit-can-MSVC-lambdas-capture... Sent from the Boost - Dev mailing list archive at Nabble.com.

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

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.

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

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 -- View this message in context: http://boost.2283326.n4.nabble.com/boost-scope-exit-can-MSVC-lambdas-capture... Sent from the Boost - Dev mailing list archive at Nabble.com.

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.

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 -- View this message in context: http://boost.2283326.n4.nabble.com/boost-scope-exit-can-MSVC-lambdas-capture... Sent from the Boost - Dev mailing list archive at Nabble.com.

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_loc... 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 -- View this message in context: http://boost.2283326.n4.nabble.com/boost-scope-exit-can-MSVC-lambdas-capture... Sent from the Boost - Dev mailing list archive at Nabble.com.

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_loc...
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?

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_loc...
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 -- View this message in context: http://boost.2283326.n4.nabble.com/boost-scope-exit-can-MSVC-lambdas-capture... Sent from the Boost - Dev mailing list archive at Nabble.com.

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
participants (5)
-
Alexander Nasonov
-
Dave Abrahams
-
lcaminiti
-
Mathias Gaunard
-
Nathan Ridge