
Hi I factored out trampoline class from my ext_auto_ptr_090 . I'd like to know how it works on modern compilers. I was able to test it on few compilers I use for regression tests: msvc71 (passed with FAULTY set) como 4.3.3 with backend msvc71 mingw 3.3.1 mingw 3.4.1RC I will be happy to know how it works with other compilers. Maybe boosters could test this code with some compilers? I'm especially interested in recent Intel and CW versions. I think that it might be useful utility in boost, provided I can make it enough functional (passing arguments to function is first thing to be added). B. #include <cassert> #include <cstdio> #include <utility> // Copyright Bronislaw Kozicki 2003-2004. Use, modification and // distribution is subject to the Boost Software License, Version // 1.0. (See http://www.boost.org/LICENSE_1_0.txt ) #ifndef __COMO__ # if defined(_MSC_VER) && (_MSC_VER <= 1310) # define FAULTY # endif // _MSC_VER #endif // __COMO__ template <bool> struct static_assert; template <> struct static_assert<true> {}; class trampoline { private: typedef void(*_pf_t)(void *); template <typename Functor> struct _lever_t; template <typename Functor> struct _lever_t<Functor *> { static_assert<sizeof(Functor*) == sizeof(void *)> size; union convert { Functor* f; void* p; }; static void exec(void * p) { convert c; c.p = p; (*c.f)(); } static std::pair<_pf_t, void *> init(Functor* f) { convert c; c.f = f; return std::pair<_pf_t, void *>(&exec, c.p); } }; // the one and the only data std::pair<_pf_t, void *> _pf; public: template <typename Functor> trampoline(Functor f) : _pf(_lever_t<Functor>::init(f)) {} trampoline(const trampoline& rh) : _pf(rh._pf) {} trampoline& operator=(const trampoline& rh) { _pf = rh._pf; return *this; } void operator()() { _pf.first(_pf.second); } }; static int tmp = 0; static const int tmp_f = 2; void f() { printf("f()\n"); tmp = tmp_f; } static const int tmp_g = 5; static const int tmp_g_f = 6; #ifdef FAULTY int g() { int i = tmp_g_f; printf("faulty "); #else int g(int i = tmp_g) { #endif tmp = i; printf("g(%d)\n", i); return tmp; } static const int tmp_A = 10; struct A { void operator()() const { printf("A::operator()()\n"); tmp = tmp_A; } }; trampoline f1() { return trampoline(&f); } trampoline g1() { return trampoline(&g); } trampoline A1() { static A a; return trampoline(&a); } int main() { trampoline l = f1(); l(); assert(tmp == tmp_f); l = g1(); l(); assert(tmp == tmp_g || tmp == tmp_g_f); l = A1(); l(); assert(tmp == tmp_A); }

From: Bronek Kozicki <brok@rubikon.pl>
#include <cassert> #include <cstdio> #include <utility>
// Copyright Bronislaw Kozicki 2003-2004. Use, modification and // distribution is subject to the Boost Software License, Version // 1.0. (See http://www.boost.org/LICENSE_1_0.txt )
#ifndef __COMO__ # if defined(_MSC_VER) && (_MSC_VER <= 1310) # define FAULTY # endif // _MSC_VER #endif // __COMO__
template <bool> struct static_assert; template <> struct static_assert<true> {};
class trampoline { private: typedef void(*_pf_t)(void *);
template <typename Functor> struct _lever_t;
template <typename Functor> struct _lever_t<Functor *> { static_assert<sizeof(Functor*) == sizeof(void *)> size;
union convert { Functor* f; void* p; };
What if a void * and a pmf are not the same size? You at least need a static assertion to that effect, right?
static void exec(void * p) { convert c; c.p = p; (*c.f)(); }
static std::pair<_pf_t, void *> init(Functor* f) { convert c; c.f = f; return std::pair<_pf_t, void *>(&exec, c.p);
^^^^^ &_lever_t::exec Unfortunately, the type of exec is void (_lever_t<Function *>::*)(void *) not void (*)(void *) as you've declared _pf_t. Thus, on any compiler that uses a different function pointer type for pointers to member functions and regular function pointers, will fail to compile this code. (I haven't tested to learn if there are any, but even if there aren't any today, there could be tomorrow.) -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

Rob Stewart wrote:
static_assert<sizeof(Functor*) == sizeof(void *)> size; ^^^^^^^^^^^^^
union convert { Functor* f; void* p; };
What if a void * and a pmf are not the same size? You at least need a static assertion to that effect, right?
Yep. I believe that it's rare, but in any case assertion is in place.
static void exec(void * p) ^^^^^^ Unfortunately, the type of exec is void (_lever_t<Function *>::*)(void *) not void (*)(void *) as you've declared _pf_t. Thus, on any compiler that uses a different function pointer type for pointers to member functions and regular function pointers, will fail to compile this code.
No. exec is static member function. I'm pretty sure that its address can be used to initialize regular function pointer, and that it's portable and guaranteed by C++ standard. Futhermore, I'm quite sure that type you mention is not applicable to static members of class. B.

Bronek Kozicki <brok@rubikon.pl> wrote:
Rob Stewart wrote:
static_assert<sizeof(Functor*) == sizeof(void *)> size; ^^^^^^^^^^^^^
union convert { Functor* f; void* p; };
What if a void * and a pmf are not the same size? You at least need a static assertion to that effect, right?
Yep. I believe that it's rare, but in any case assertion is in place.
On most compilers the rarity is when the size of function pointer equals to the size of member function pointer. See http://www.codeproject.com/cpp/FastDelegate.asp for reference. Anyway, it looks like the trampoline is not supposed to work with pointers to non static member functions at all, since it requires passing the object to apply the pointer to. Or am I missing something? -- Maxim Yegorushkin

Bronek Kozicki wrote:
Yep. I believe that it's rare, but in any case assertion is in place.
I wouldn't consider it all that rare. For instance VC++ line of compilers user 12 byte pointers when dealing with pointer to members of classes involving virtual base classes. And 8 bytes for pointer to members involving multiple inheritance. David

David Bradley wrote:
Yep. I believe that it's rare, but in any case assertion is in place.
I wouldn't consider it all that rare. For instance VC++ line of compilers user 12 byte pointers when dealing with pointer to members of classes involving virtual base classes. And 8 bytes for pointer to members involving multiple inheritance.
OK, when dealing with pointers to memmbers I will remember about it. Hm, &operator() is pointer to member, anyway ... B.

Bronek Kozicki <brok@rubikon.pl> writes:
Rob Stewart wrote:
static_assert<sizeof(Functor*) == sizeof(void *)> size; ^^^^^^^^^^^^^
union convert { Functor* f; void* p; };
What if a void * and a pmf are not the same size? You at least need a static assertion to that effect, right?
Yep. I believe that it's rare, but in any case assertion is in place.
Why mess around? You don't need to use a void*; just use a void(X::*)(void) for any X. Round-trip reinterpret_cast is guaranteed to work. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
Why mess around? You don't need to use a void*; just use a void(X::*)(void) for any X. Round-trip reinterpret_cast is guaranteed to work.
Well I don't think this is guarenteed sizeof(void (X::*)(void) == sizeof(void (Y::*)(void). But I'm basing my assumption the VC++ compilers implementation which is often a risky thing to do. VC++'s pointer to members vary in size based on the type, mainly plain inheritance, multiple inheritance and virtual base class involvement. David

David Bradley <BradleyJunk@cinci.rr.com> writes:
David Abrahams wrote:
Why mess around? You don't need to use a void*; just use a void(X::*)(void) for any X. Round-trip reinterpret_cast is guaranteed to work.
Well I don't think this is guarenteed sizeof(void (X::*)(void) == sizeof(void (Y::*)(void). But I'm basing my assumption the VC++ compilers implementation which is often a risky thing to do.
Just read the standard. What I said holds. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
Just read the standard. What I said holds.
Well it's at the office and I'm at home, but I'll take your word for it. Regardless of the standard his code is not going to work on Visual Studio 2003 C++ which was one of the compilers he was interested in. David Bradley

David Bradley wrote:
Regardless of the standard his code is not going to work on Visual Studio 2003 C++ which was one of the compilers he was interested in.
Well, I tested it on MSVC71 and it worked fine :> Currently I'm not using pointer-to-member, as the only member function being called is operator(). See code at the beginning of this thread again, thanks. One thing more: macro "FAULTY" should be actually named "COMPLIANT". B.

David Abrahams <dave@boost-consulting.com> wrote:
David Bradley <BradleyJunk@cinci.rr.com> writes:
David Abrahams wrote:
Why mess around? You don't need to use a void*; just use a void(X::*)(void) for any X. Round-trip reinterpret_cast is guaranteed to work.
Well I don't think this is guarenteed sizeof(void (X::*)(void) == sizeof(void (Y::*)(void). But I'm basing my assumption the VC++ compilers implementation which is often a risky thing to do.
Just read the standard. What I said holds.
Only with /vmg command-line switch for VC7+ or pragmas (http://msdn.microsoft.com/library/en-us/vccore/html/_core_.2f.vmb.2c_2f.vmg....) -- Maxim Yegorushkin

From: Bronek Kozicki <brok@rubikon.pl>
Rob Stewart wrote:
static void exec(void * p) ^^^^^^ Unfortunately, the type of exec is void (_lever_t<Function *>::*)(void *) not void (*)(void *) as you've declared _pf_t. Thus, on any compiler that uses a different function pointer type for pointers to member functions and regular function pointers, will fail to compile this code.
No. exec is static member function. I'm pretty sure that its address can be used to initialize regular function pointer, and that it's portable and guaranteed by C++ standard. Futhermore, I'm quite sure that type you mention is not applicable to static members of class.
You're entirely correct. I glossed right over "static." -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;
participants (5)
-
Bronek Kozicki
-
David Abrahams
-
David Bradley
-
Maxim Yegorushkin
-
Rob Stewart