[scope_exit] MSVC error C2355: 'this' : can only be referenced inside non-static member functions

Hello all, I am trying to use Boost.ScopeExit parameter binding mechanism to implement Boost.LocalFunction. To do so, I need to use some internal ScopeExit code to detect the type of `this` and bind its value to the local function declaration. The following code works on GCC but not on MSVC... This appears to be a MSVC 2008 bug: http://connect.microsoft.com/VisualStudio/feedback/details/331418/erroneous-... 1) Can anyone please try this code on MSVC versions later than 2008 to see if it was fixed? 2) Do you know of a workaround for this problem? // File: lf03.cpp #include <boost/scope_exit.hpp> struct c { void f() { typedef void (*this_t)(int this_ ); #if defined(BOOST_MSVC) // for MSVC typedef boost::type_of::msvc_typeid_wrapper< sizeof(*boost::type_of::encode_start( #else // for GCC typedef __typeof__( boost::type_of::ensure_obj( #endif boost::scope_exit::aux::wrap( boost::scope_exit::aux::deref( this, (this_t)0 ) ) ) #if defined(BOOST_MSVC) // for MSVC )>::type #else // for GCC ) #endif this_w; } }; int main() { c cc; cc.f(); return 0; } I get this error on MSVC 2008 but the code compiles just fine on GCC: Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.42 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. lf03.cpp using native typeof lf03.cpp(17) : error C2355: 'this' : can only be referenced inside non-static member functions lf03.cpp(22) : error C2955: 'boost::type_of::msvc_typeid_wrapper' : use of class template requires template argument list C:\Program Files\boost\boost_1_42\boost/typeof/msvc/typeof_impl.hpp(212) : see declaration of 'boost::type_of::msvc_typeid_wrapper' Thank you very much. -- Lorenzo

On Wed, Aug 25, 2010 at 7:49 PM, Lorenzo Caminiti <lorcaminiti@gmail.com> wrote:
Hello all,
I am trying to use Boost.ScopeExit parameter binding mechanism to implement Boost.LocalFunction. To do so, I need to use some internal ScopeExit code to detect the type of `this` and bind its value to the local function declaration.
The following code works on GCC but not on MSVC... This appears to be a MSVC 2008 bug: http://connect.microsoft.com/VisualStudio/feedback/details/331418/erroneous-...
1) Can anyone please try this code on MSVC versions later than 2008 to see if it was fixed? 2) Do you know of a workaround for this problem?
// File: lf03.cpp
#include <boost/scope_exit.hpp>
struct c { void f() { typedef void (*this_t)(int this_ );
#if defined(BOOST_MSVC) // for MSVC typedef boost::type_of::msvc_typeid_wrapper< sizeof(*boost::type_of::encode_start( #else // for GCC typedef __typeof__( boost::type_of::ensure_obj( #endif boost::scope_exit::aux::wrap( boost::scope_exit::aux::deref( this, (this_t)0 ) ) ) #if defined(BOOST_MSVC) // for MSVC )>::type #else // for GCC ) #endif this_w; } };
int main() { c cc; cc.f(); return 0; }
I get this error on MSVC 2008 but the code compiles just fine on GCC:
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.42 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved.
lf03.cpp using native typeof lf03.cpp(17) : error C2355: 'this' : can only be referenced inside non-static member functions lf03.cpp(22) : error C2955: 'boost::type_of::msvc_typeid_wrapper' : use of class template requires template argument list C:\Program Files\boost\boost_1_42\boost/typeof/msvc/typeof_impl.hpp(212) : see declaration of 'boost::type_of::msvc_typeid_wrapper'
Thank you very much.
-- Lorenzo
BTW, the point of this code is to automatically determine the type of `this`. However, all the workarounds I found of the Internet assume to know the type `c*` of this by doing: struct c { void f() { c& self = *this; ... // Use `self` instead of `this` in the type determination code -- but I already know the type `c` since I used it above... } }; so I cannot use these type of workarounds. -- Lorenzo

[Lorenzo Caminiti]
I get this error on MSVC 2008 but the code compiles just fine on GCC: Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.42 for 80x86
That's not 2008, it's 2005 (and it's 2005 RTM). _MSC_VER == 1400, VC8, VS 2005 _MSC_VER == 1500, VC9, VS 2008 _MSC_VER == 1600, VC10, VS 2010 (Our C++ compiler predates *Visual* C++.) This compiles with VC10 and Boost 1.44.0: C:\Temp>type meow.cpp #include <boost/scope_exit.hpp> struct c { void f() { typedef void (*this_t)(int this_ ); #if defined(BOOST_MSVC) // for MSVC typedef boost::type_of::msvc_typeid_wrapper< sizeof(*boost::type_of::encode_start( #else // for GCC typedef __typeof__( boost::type_of::ensure_obj( #endif boost::scope_exit::aux::wrap( boost::scope_exit::aux::deref( this, (this_t)0 ) ) ) #if defined(BOOST_MSVC) // for MSVC )>::type #else // for GCC ) #endif this_w; } }; int main() { c cc; cc.f(); return 0; } C:\Temp>cl /EHsc /nologo /W4 /I . meow.cpp meow.cpp using native typeof C:\Temp>meow C:\Temp> Stephan T. Lavavej Visual C++ Libraries Developer

On 8/25/2010 8:04 PM, Stephan T. Lavavej wrote:
[Lorenzo Caminiti]
I get this error on MSVC 2008 but the code compiles just fine on GCC: Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.42 for 80x86
That's not 2008, it's 2005 (and it's 2005 RTM).
<snip>
This compiles with VC10 and Boost 1.44.0: <snip>
I reported this vc9 bug to Microsoft at the time. They closed it "won't fix". Glad to see vc10 does better. https://connect.microsoft.com/VisualStudio/feedback/details/331418/erroneous... -- Eric Niebler BoostPro Computing http://www.boostpro.com

On Thu, August 26, 2010 12:49 am, Lorenzo Caminiti wrote:
I am trying to use Boost.ScopeExit parameter binding mechanism to implement Boost.LocalFunction. To do so, I need to use some internal ScopeExit code to detect the type of `this` and bind its value to the local function declaration.
<snip>
2) Do you know of a workaround for this problem?
I posted a workaround for this a while back (http://lists.boost.org/Archives/boost/2009/03/149540.php) which used type indexing (where the index for typeof(this) is captured outside of a template parameter list) to avoid specifying 'this' in a template parameter list. The mechanics for the solution came from boost.typeof. However, the 'most preferred/natural syntax' relied on the somewhat rude definition of a function-style macro named 'this' (to support detection of the presence of 'this' as the first element of a preprocessor sequence) which, whilst innocuous, violates 17.4.3.1.1: 'Nor shall such a translation unit define macros for names lexically identical to keywords.' This may not be an issue for localfunction if you are always capturing 'this' or have a distinct interface for it's use in member functions. I have attached my latest version of the patch which still applies fine to 1.44 and, I think, works on cl versions from vc7.1 upwards. You should be able to use the same type index trick in localfunction. The key definition is the function-style macro BOOST_SCOPE_EXIT_TYPEDEF_TYPEOF_THIS(). Regards Adam

On Thu, Aug 26, 2010 at 11:52 AM, Adam Butcher <dev.lists@jessamine.co.uk> wrote:
On Thu, August 26, 2010 12:49 am, Lorenzo Caminiti wrote:
I am trying to use Boost.ScopeExit parameter binding mechanism to implement Boost.LocalFunction. To do so, I need to use some internal ScopeExit code to detect the type of `this` and bind its value to the local function declaration.
<snip>
2) Do you know of a workaround for this problem?
I posted a workaround for this a while back (http://lists.boost.org/Archives/boost/2009/03/149540.php) which used type indexing (where the index for typeof(this) is captured outside of a template parameter list) to avoid specifying 'this' in a template parameter list. The mechanics for the solution came from boost.typeof. However, the 'most preferred/natural syntax' relied on the somewhat rude definition of a function-style macro named 'this' (to support detection of the presence of 'this' as the first element of a preprocessor sequence) which, whilst innocuous, violates 17.4.3.1.1: 'Nor shall such a translation unit define macros for names lexically identical to keywords.' This may not be an issue for localfunction if you are always capturing 'this' or have a distinct interface for it's use in member functions.
You should also be able to modify your patch to use the following `IS_TRAILING_THIS` macro to check if `this` is passed within the `SCOPE_EXIT` sequence so you don't have to `#define this() ...`: #include <boost/preprocessor/detail/is_unary.hpp> #include <boost/preprocessor/cat.hpp> #define this_CONTRACT_DETAIL_PP_KEYWORD_THIS (1) #define CONTRACT_DETAIL_PP_KEYWORD_CHECK_BACK(tokens, keyword_postfix) \ BOOST_PP_IS_UNARY(BOOST_PP_CAT(tokens, keyword_postfix)) #define CONTRACT_DETAIL_PP_KEYWORD_IS_TRAILING_THIS(tokens) \ CONTRACT_DETAIL_PP_KEYWORD_CHECK_BACK(tokens, \ _CONTRACT_DETAIL_PP_KEYWORD_THIS) Given `SCOPE_EXIT(seq)` you can `SEQ_FOR_EACH(..., seq)` and apply `IS_TRAILING_THIS(elem)` for each `elem` in `seq`. Then `IS_TRAILING_THIS(this)` will expand to 1 while `IS_TRAILING(x)` `IS_TRAILING(&x)`, etc will all expand to 0. So you can check if an elem of seq is the token `this` or not and if it is you expand the `SCOPE_EXIT` to code that handles `this` (as you do now in your patch but without relying of `#define this() ...`).
I have attached my latest version of the patch which still applies fine to 1.44 and, I think, works on cl versions from vc7.1 upwards.
You should be able to use the same type index trick in localfunction. The key definition is the function-style macro BOOST_SCOPE_EXIT_TYPEDEF_TYPEOF_THIS().
Yes, I got the following example to compile: #include <contract/detail/se/scope_exit.hpp> // This header uses you patch for both scope_exit and typeof. //#include <boost/scope_exit.hpp> #include <iostream> struct c { c(): x_(0) {} bool eq(int x) { std::cout << "eq" << std::endl; return x_ == x; } void f(int& x) { std::cout << "f" << std::endl; x = -1; BOOST_SCOPE_EXIT( (this)(&x) ) { if (x < 0) x = 0; // These don't work :( //eq(x); //this->eq(x); //(*this).eq(x); // These work but syntax is not natural... operator->()->eq(x); operator*()->eq(x); std::cout << "se" << std::endl; } BOOST_SCOPE_EXIT_END } private: int x_; }; int main() { c cc; int x = 0; cc.f(x); return 0; } However, the syntax to access the object `this` inside scope exit needs to explicitly call the `operator->` or `operator*`... that's ugly so I am using a special name `this_` inside my local functions. *** Am I missing something? Can you access `this` from within the scope exit code without calling the operators directly? *** -- Lorenzo

On Thu, August 26, 2010 12:49 am, Lorenzo Caminiti wrote:
I am trying to use Boost.ScopeExit parameter binding mechanism to implement Boost.LocalFunction. To do so, I need to use some internal ScopeExit code to detect the type of `this` and bind its value to the local function declaration.
<snip>
2) Do you know of a workaround for this problem?
I posted a workaround for this a while back (http://lists.boost.org/Archives/boost/2009/03/149540.php) which used type indexing (where the index for typeof(this) is captured outside of a template parameter list) to avoid specifying 'this' in a template parameter list. The mechanics for the solution came from boost.typeof.
<snip>
I have attached my latest version of the patch which still applies fine to 1.44 and, I think, works on cl versions from vc7.1 upwards.
You should be able to use the same type index trick in localfunction. The key definition is the function-style macro BOOST_SCOPE_EXIT_TYPEDEF_TYPEOF_THIS().
Why is this patch defining the following accessors for the ScopeExit local struct? +#define BOOST_SCOPE_EXIT_DEFINE_THIS_ACCESSOR_this(id) \ + inline BOOST_PP_CAT(se_this_type,id) operator->() { return boost_se_params_->se_this; } \ + inline BOOST_PP_CAT(se_this_type,id) operator*() { return boost_se_params_->se_this; } \ + inline operator BOOST_PP_CAT(se_this_type,id)() { return boost_se_params_->se_this; } \ I think these are meant to use `this` to access the bound object instead of the local struct object. However, these accessors don't work because `this->` (and `*this`) never calls the overloaded `operator->`: #include <iostream> struct obj_t { int x; int f() { return -1; } } obj; typedef obj_t* this_t; int main() { struct l { void operator()() { std::cout << this->x << std::endl; // error :(( std::cout << this->f() << std::endl; // error :(( std::cout << this->operator->()->x << std::endl; // ok std::cout << this->operator->()->f() << std::endl; // ok } this_t operator->() { return &obj; } this_t operator*() { return &obj; } operator this_t() { return &obj; } int f; } ll; ll(); return 0; } Am I not understanding the purpose of the patch's assessors correctly? Thanks for the clarification. -- Lorenzo -- View this message in context: http://boost.2283326.n4.nabble.com/scope-exit-MSVC-error-C2355-this-can-only... Sent from the Boost - Dev mailing list archive at Nabble.com.

On Tue, March 1, 2011 4:38 pm, lcaminiti wrote:
On Thu, August 26, 2010 12:49 am, Lorenzo Caminiti wrote:
I am trying to use Boost.ScopeExit parameter binding mechanism to implement Boost.LocalFunction. To do so, I need to use some internal ScopeExit code to detect the type of `this` and bind its value to the local function declaration.
<snip>
2) Do you know of a workaround for this problem?
I posted a workaround for this a while back (http://lists.boost.org/Archives/boost/2009/03/149540.php) which used type indexing (where the index for typeof(this) is captured outside of a template parameter list) to avoid specifying 'this' in a template parameter list. The mechanics for the solution came from boost.typeof.
<snip>
You should be able to use the same type index trick in localfunction. The key definition is the function-style macro BOOST_SCOPE_EXIT_TYPEDEF_TYPEOF_THIS().
Why is this patch defining the following accessors for the ScopeExit local struct?
[snip]
I think these are meant to use `this` to access the bound object instead of the local struct object. However, these accessors don't work because `this->` (and `*this`) never calls the overloaded `operator->`:
[snip]
Am I not understanding the purpose of the patch's assessors correctly?
At the time the suggest syntax for accessing the enclosing class' this-pointer was the expression (*this) So from within the scope-exit you would use (*this) as the object of the enclosing class (rather than plain 'this' which refers to the instance of the scope-exit class). Though contentious, this was my best effort at the time to get the word 'this' into member accesses. Other suggestions IIRC where calling explicit functions such as enclosing_this()-> or this_()-> or having those names as pointer members (i.e. enclosing_this->, or this_->). The reason for the implicit conversion to reference-to the enclosing instance was to allow passing of (*this) to functions that expected a pointer or reference to the enclosing class. Hope this helps. Cheers, Adam

Adam Butcher-2 wrote:
On Tue, March 1, 2011 4:38 pm, lcaminiti wrote:
On Thu, August 26, 2010 12:49 am, Lorenzo Caminiti wrote:
I am trying to use Boost.ScopeExit parameter binding mechanism to implement Boost.LocalFunction. To do so, I need to use some internal ScopeExit code to detect the type of `this` and bind its value to the local function declaration.
<snip>
2) Do you know of a workaround for this problem?
I posted a workaround for this a while back (http://lists.boost.org/Archives/boost/2009/03/149540.php) which used type indexing (where the index for typeof(this) is captured outside of a template parameter list) to avoid specifying 'this' in a template parameter list. The mechanics for the solution came from boost.typeof.
<snip>
You should be able to use the same type index trick in localfunction. The key definition is the function-style macro BOOST_SCOPE_EXIT_TYPEDEF_TYPEOF_THIS().
Why is this patch defining the following accessors for the ScopeExit local struct?
[snip]
I think these are meant to use `this` to access the bound object instead of the local struct object. However, these accessors don't work because `this->` (and `*this`) never calls the overloaded `operator->`:
[snip]
Am I not understanding the purpose of the patch's assessors correctly?
At the time the suggest syntax for accessing the enclosing class' this-pointer was the expression
(*this)
So from within the scope-exit you would use (*this) as the object of the enclosing class (rather than plain 'this' which refers to the instance of the scope-exit class). Though contentious, this was my best effort at the time to get the word 'this' into member accesses. Other suggestions IIRC where calling explicit functions such as enclosing_this()-> or this_()-> or having those names as pointer members (i.e. enclosing_this->, or this_->).
The reason for the implicit conversion to reference-to the enclosing instance was to allow passing of (*this) to functions that expected a pointer or reference to the enclosing class.
OK, I understand now. I am using `this_` in my application (Boost.Local) and I will keep that syntax. (FYI, there is a mechanism to use the plain `this` to assess the bound object but it relies on an unsafe `static_cast<>` -- see http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/...) Thanks a lot for the clarification! -- Lorenzo -- View this message in context: http://boost.2283326.n4.nabble.com/scope-exit-MSVC-error-C2355-this-can-only... Sent from the Boost - Dev mailing list archive at Nabble.com.
participants (5)
-
Adam Butcher
-
Eric Niebler
-
lcaminiti
-
Lorenzo Caminiti
-
Stephan T. Lavavej