How to save member pointer at compile time?

Consider the following code

template<typename T, int N> struct A { typedef T value_type; // OK. save T to value_type static const int size = N; // OK. save N to size }; 

Look, you can save any template parameter if this parameter is a type name or an integer value. The fact is that a pointer to a member is an offset, i.e. Integer. Now I want to save any member pointer at compile time:

 struct Foo { int m; int r; }; template<int Foo::*ptr_to_member> struct B { // Next statement DOES NOT WORK! static int Foo::* const saved_ptr_to_member = ptr_to_member; }; // Example of using int main() { typedef B<&Foo::m> Bm; typedef B<&Foo::r> Br; Foo foo; std::cout << (foo.*(Bm::saved_ptr_to_member)); } 

How to save member pointer at compile time ? I am using VS2008.

Note. Compilation time is critical. Please do not record the solution at runtime. I know it.

+6
c ++ templates pointer-to-member
source share
4 answers

Why use a template?

 #include <cstdio> struct Foo { int a; int b; } foo = {2, 3}; int const (Foo::*mp) = &Foo::b; int main() { printf("%d\n", foo.*mp); return 0; } 

The following mp compiles to this on gcc-4.4.1 (I do not have access to MSVC at the moment):

 .globl mp .align 4 .type mp, @object .size mp, 4 mp: .long 4 

This is just a member offset that looks pretty compiled for me.

With a template, you need to specify a definition outside the class:

 #include <cstdio> struct Foo { int m; int r; } foo = {2, 3}; template<int Foo::*Mem> struct B { static int Foo::* const mp; }; template<int Foo::*Mem> int Foo::* const B<Mem>::mp = Mem; int main() { typedef B<&Foo::m> Bm; typedef B<&Foo::r> Br; printf("%d, %d\n", foo.*(Bm::mp), foo.*(Br::mp)); } 

What compiles:

 g++ -O2 -S -o- b.cc | c++filt ... .weak B<&(Foo::r)>::mp .section .rodata._ZN1BIXadL_ZN3Foo1rEEEE2mpE,"aG",@progbits,B<&(Foo::r)>::mp,comdat .align 4 .type B<&(Foo::r)>::mp, @object .size B<&(Foo::r)>::mp, 4 B<&(Foo::r)>::mp: .long 4 .weak B<&(Foo::m)>::mp .section .rodata._ZN1BIXadL_ZN3Foo1mEEEE2mpE,"aG",@progbits,B<&(Foo::m)>::mp,comdat .align 4 .type B<&(Foo::m)>::mp, @object .size B<&(Foo::m)>::mp, 4 B<&(Foo::m)>::mp: .zero 4 

However, this all resembles the re-implementation of standard libraries (see std::tr1::mem_fn ).

0
source share

You can not.

But instead you can use functionoid . It may be a compilation solution. And since the compiler can inline things, perhaps even faster than a pointer to a member function. Example:

 struct Foo { int m; int r; }; struct FooM { static int call(Foo const &foo) const { return foo.m; } } struct FooR { static int call(Foo const &foo) const { return foo.r; } } template<typename FooFun> struct B { typedef FooFun foo_fun; int call_foo_fun(Foo const &foo) { return foo_fun::call(foo); } }; // Example of using int main() { typedef B<FooM> Bm; typedef B<FooR> Br; Foo foo; std::cout << Bm.call_foo_fun(foo); } 

Unconfirmed, but you get the idea.

+1
source share

It would be nice to have a more detailed explanation of why compilation time is important (helps suggest alternatives). But, in my opinion, all you need to do, compile time with a member pointer, you really can do. My option is Thomas' suggestion mixed with some C ++ philosophy. First, let's define:

 template <typename T, T v> struct val {}; 

this structure template can effectively serve as a compile-time value, and you do not need β€œstatic value = v;” to use it either at compile time or at run time. Consider:

 template <int n> struct Foo { //something dependent on n }; 

and

 template <typename T> struct Bar; template <int n> struct Bar <val <int, n> > { //something dependent of n }; 

Foo and Bar are functionally equivalent, each metadabra template that can be done with Foo can also be done with Bar (just skip val instead of n). In the same vay you can pack a pointer to a member in val <>:

 val <typeof (&My::a), &My::a> 

these compilation time values ​​can now be stored in type lists (for example, boost :: mpl :: something), compared, converted, etc., all the time compilation. And when you finally want to use them as a pointer to an element at runtime, just define one function template:

 template <typename T, T value> T extract (val <T, value>) { return value; } 

and use it:

 typedef val <typeof (A::i), A::i> a_i; A a; std::cout << (a .* extract (a_i ())); 

PS: There are some clumsy constructions about this solution, but all for the sake of simplicity and explanation. For example, pretty ugly (a. * Extract (a_i ())) can be simplified by moving it to something more specific to a member pointer:

 template <typename M, typename C> typename mem_type <M>::value & mem_apply (C &c) { M m; return c .* extract (m); } 

where mem_type is the class template that retrieves the type of the member referenced by M. Then use will be:

 std::cout << mem_apply <a_i> (a); 
+1
source share

You cannot initialize a static member inside a structure definition. It should be declared outside of this (which is probably not the way you planned with the template, but anyway):

 struct Foo { int m; int r; }; template<int Foo::*ptr_to_member> struct B { static int Foo::* const saved_ptr_to_member; }; int Foo::* const B<&Foo::m>::saved_ptr_to_member = &Foo::m; int Foo::* const B<&Foo::r>::saved_ptr_to_member = &Foo::r; // Example of using int main() { typedef B<&Foo::m> Bm; typedef B<&Foo::r> Br; Foo foo; std::cout << (foo.*(Bm::saved_ptr_to_member)); } 
0
source share

All Articles