[scope_exit] capture list syntax for scope_exit and local_function

gmane wrote:
The following errors were found. Fix them, and submit again: You seem to be top-posting. Don't do that. apparently gmane bug.
Hi, My current implementation uses ref/cref/val prefixes to pass arguments. It's not consistent with C++0x lambda capture list syntax. scope_exit: (ref a)(cref b)(val c) c++0x: [&a, &b, c] I have a proof-of-concept implementation for BOOST_SCOPE_EXIT( (&a)(&b)(c) ) { std::cout << a << '\n' << b << '\n' << c << '\n'; } BOOST_SCOPE_EXIT_END It does not support passing by reference of classes with overloaded unary operator& but they are rather rare and we can tell users to use reference_wrapper to pass them. Also, it does indirect function call. Gcc 3.4 and 4.2 don't optimize it away even with -O3 but Intel 10.1 does (though, it generates a body of the function even with -Os). What do you think? #include <iostream> #include <boost/mpl/if.hpp> #include <boost/call_traits.hpp> #include <boost/type_traits/is_function.hpp> template<class T> inline T& deref(T* p, boost::false_type) { return *p; } template<class T> inline T& deref(T& r, boost::true_type) { return r; } void foo(int a, long const b, char const c) { int &a_ref_test(); int &b_ref_test(); int c_ref_test(); typedef boost::is_function<typeof(&a_ref_test)> is_not_ref_0; typedef boost::is_function<typeof(&b_ref_test)> is_not_ref_1; typedef boost::is_function<typeof( c_ref_test)> is_not_ref_2; typedef typeof(deref(&a, is_not_ref_0())) value_t_0; typedef typeof(deref(&b, is_not_ref_1())) value_t_1; typedef typeof(deref( c, is_not_ref_2())) value_t_2; typedef boost::mpl::if_< is_not_ref_0, boost::call_traits<value_t_0>::param_type, value_t_0
::type param_t_0;
typedef boost::mpl::if_< is_not_ref_1, boost::call_traits<value_t_1>::param_type, value_t_1
::type param_t_1;
typedef boost::mpl::if_< is_not_ref_2, boost::call_traits<value_t_2>::param_type, value_t_2
::type param_t_2;
struct params_t { value_t_0 &a; value_t_1 &b; value_t_2 c; params_t(param_t_0 &a, param_t_1 &b, param_t_2 c) : a(a), b(b), c(c) {} void invoke(void (*f)(param_t_0 &a, param_t_1 &b, param_t_2 c)) { f( deref(&a, is_not_ref_0()), deref(&b, is_not_ref_1()), deref( c, is_not_ref_2()) ); } }; params_t params( deref(&a, is_not_ref_0()), deref(&b, is_not_ref_1()), deref( c, is_not_ref_2()) ); void* p = ¶ms; struct guard_t { params_t* params; guard_t(void* p) : params((params_t*)p) {} ~guard_t() { params->invoke(&guard_t::body); } static void body(param_t_0 &a, param_t_1 &b, param_t_2 c) { std::cout << a << '\n' << b << '\n' << c << '\n'; } } guard(p); } int main() { foo(0, 1, '2'); } Thanks, Alex

Alexander Nasonov <alnsn <at> yandex.ru> writes:
I have a proof-of-concept implementation for
BOOST_SCOPE_EXIT( (&a)(&b)(c) ) { std::cout << a << '\n' << b << '\n' << c << '\n'; } BOOST_SCOPE_EXIT_END
Hi, I managed to fix gcc ICEs and to get rid of indirect function call by following my previous code more closely. And I love the new code and the new syntax, they'll make a transition to c++0x much smoother. I have a couple of things in my TODO list but they can wait for the next release. See my commit to trunk: https://svn.boost.org/trac/boost/changeset/50620 I appreciate if people can run regression tests, especially on Windows because I don't use Windows at the moment. The sooner we get results for supported compilers/platforms the bigger is change that release managers will approve it for *this* release. Note that I missed status/Jamfile.v2. Before running regression.py, please make sure that scope_exit entry is in the file or add it manually. I'll commit as soon as I get back to home. Below you can find a human-readable expansion of the ScopeExit block quoted above. Thanks, Alex #include <boost/typeof/typeof.hpp> #if defined(__GNUC__) && !defined(__ICC) #define TPL_WORKAROUND #endif #if defined(TPL_WORKAROUND) // What are you testing, BOOST_SCOPE_EXIT or BOOST_SCOPE_EXIT_TPL? //#define TYPENAME #define TYPENAME typename #else #define TYPENAME #endif typedef void (*ref_tag)(int&); typedef void (*val_tag)(int ); template<class T, class Tag> struct member; template<class T> struct member<T,ref_tag> { T& value; #if !defined(TPL_WORKAROUND) member(T& ref) : value(ref) {} #endif }; template<class T> struct member<T,val_tag> { T value; #if !defined(TPL_WORKAROUND) member(T& val) : value(val) {} #endif }; template<class T> struct wrapper { typedef T type; }; #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP() BOOST_TYPEOF_REGISTER_TEMPLATE(wrapper, 1) template<class T> wrapper<T> wrap(T&); template<class T> inline T& deref(T* p, void (*)(int&)) { return *p; } template<class T> inline T& deref(T& r, void (*)(int )) { return r; } // TODO: Change return type of deref to member<T,tag> and get rid of wrap #include <iostream> // What are you testing, BOOST_SCOPE_EXIT or BOOST_SCOPE_EXIT_TPL? //typedef int A; typedef int B; template<class A, class B> void foo(A& a, B const& b) { char c = 0; // Input: (&a)(&b)(c) typedef void (*tag_0)(int &a); typedef void (*tag_1)(int &b); typedef void (*tag_2)(int c); #if defined(BOOST_TYPEOF_NATIVE) // Note: BOOST_TYPEOF_KEYWORD should not strip const // if deref returns T const& typedef BOOST_TYPEOF_KEYWORD(deref(&a, (tag_0)0)) capture_t_0; typedef BOOST_TYPEOF_KEYWORD(deref(&b, (tag_1)0)) capture_t_1; typedef BOOST_TYPEOF_KEYWORD(deref( c, (tag_2)0)) capture_t_2; #else struct wrapped_t_0 : BOOST_TYPEOF(wrap(deref(&a, (tag_0)0))) {}; struct wrapped_t_1 : BOOST_TYPEOF(wrap(deref(&b, (tag_1)0))) {}; struct wrapped_t_2 : BOOST_TYPEOF(wrap(deref( c, (tag_2)0))) {}; typedef TYPENAME wrapped_t_0::type capture_t_0; typedef TYPENAME wrapped_t_1::type capture_t_1; typedef TYPENAME wrapped_t_2::type capture_t_2; #endif struct params_t { typedef capture_t_0 param_t_0; typedef capture_t_1 param_t_1; typedef capture_t_2 param_t_2; member<param_t_0,tag_0> param_0; member<param_t_1,tag_1> param_1; member<param_t_2,tag_2> param_2; #if !defined(TPL_WORKAROUND) params_t(param_t_0& a0, param_t_1& a1, param_t_2& a2) : param_0(a0), param_1(a1), param_2(a2) {} #endif } params #if defined(TPL_WORKAROUND) = { { deref(&a, (tag_0)0) }, { deref(&b, (tag_1)0) }, { deref( c, (tag_2)0) } }; #else ( deref(&a, (tag_0)0), deref(&b, (tag_1)0), deref( c, (tag_2)0) ); #endif void* p = ¶ms; // real code uses Watanabe's trick struct guard_t { params_t* params_; guard_t(void* p) : params_((params_t*)p) {} ~guard_t() { guard_t::body( params_->param_0.value, params_->param_1.value, params_->param_2.value ); } // TODO: don't pass c by value static void body( TYPENAME params_t::param_t_0 &a, TYPENAME params_t::param_t_1 &b, TYPENAME params_t::param_t_2 c ) { // user's code std::cout << a << '\n' << b << '\n' << c << '\n'; } } guard(p); } int main() { int i = 0; foo(i, 1u); }

Alexander Nasonov wrote:
Alexander Nasonov <alnsn <at> yandex.ru> writes:
I appreciate if people can run regression tests, especially on Windows because I don't use Windows at the moment.
I just tried manually running the tests with VC9, and got a bunch of errors. for example: native.cpp using native typeof native.cpp(38) : warning C4003: not enough actual parameters for macro 'BOOST_PP_SEQ_ELEM_0' native.cpp(38) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int native.cpp(38) : error C2513: 'int' : no variable declared before '=' native.cpp(38) : error C2146: syntax error : missing ';' before identifier 'boost_se_capture_t_0_38' native.cpp(38) : error C2065: 'boost_se_capture_t_0_38' : undeclared identifier native.cpp(38) : error C2146: syntax error : missing ';' before identifier 'boost_se_param_t_0_38' native.cpp(38) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int native.cpp(38) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int native.cpp(38) : error C2065: 'boost_se_param_t_0_38' : undeclared identifier native.cpp(38) : error C2079: 'test_non_local::boost_se_params_t_38::boost_se_param_0_38' uses undefined struct 'boost::scope_exit::aux::member' native.cpp(38) : error C2061: syntax error : identifier 'boost_se_param_t_0_38' native.cpp(38) : error C2664: 'test_non_local::boost_se_params_t_38::test_non_local::boost_se_params_t_38(const test_non_local::boost_se_params_t_38 &)' : cannot convert parameter 1 from 'int' to 'const test_non_local::boost_se_params_t_38 &' Reason: cannot convert from 'int' to 'const test_non_local::boost_se_params_t_38' No constructor could take the source type, or constructor overload resolution was ambiguous native.cpp(38) : error C2039: 'boost_se_param_t_0_38' : is not a member of 'test_non_local::boost_se_params_t_38' native.cpp(38) : see declaration of 'test_non_local::boost_se_params_t_38' native.cpp(38) : error C2061: syntax error : identifier 'boost_se_param_t_0_38' Theres quite a lot of errors, as well as a lot of "warning C4003: not enough actual parameters for macro 'BOOST_PP_SEQ_ELEM_0'" warnings. Thanks, Richard Webb -- View this message in context: http://www.nabble.com/-scope_exit--capture-list-syntax-for-scope_exit-and-lo... Sent from the Boost - Dev mailing list archive at Nabble.com.

Richard Webb <richard.webb <at> boldonjames.com> writes:
I just tried manually running the tests with VC9, and got a bunch of errors. for example:
native.cpp using native typeof
Hi Richard, Thanks for the report. Can you send me the preprocessed output off-list, please? Alex

Alexander Nasonov wrote:
Alexander Nasonov <alnsn <at> yandex.ru> writes:
See my commit to trunk: https://svn.boost.org/trac/boost/changeset/50620
I appreciate if people can run regression tests, especially on Windows because I don't use Windows at the moment.
I took a quick look at the scope_exit.hpp. If you are using __LINE__ to compose unique identifier names, then this will not wort on VC 7.1 and later with /ZI. __COUNTER__ should be used instead.
participants (3)
-
Alexander Nasonov
-
Andrey Semashev
-
Richard Webb