views:

206

answers:

3

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, it is possible to save any template parameter if this parameter is a typename or an integer value. The thing is that pointer to member is an offset, i.e. integer. Now I want to save any pointer to member in 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 pointer to member in compile time? I use VS2008.

Note. Compile time is critical. Please don't write run-time solution. I know it.

+1  A: 

You can't.

But you can use a functionoid instead. This can be a compile-time solution. And because the compiler can inline things, it's possibly 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);
}

Untested, but you get the idea.

Thomas
Functinoid is run-time solution. I asked you not to write run-time solutions.
Alexey Malistov
See my edited post.
Thomas
A: 

You can't initialize a static member inside the definition of a struct. It needs to be declared outside like this (which is probably not what you intended 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));
}
1) It is run-time solution. 2) This method does not use the advantages of templates. I must define a new pointer to member every time for the case of a new struct and members.
Alexey Malistov
1) no, it's not.2) true, but that was the originally design, now written in a way the compiler understands it. I don't see any reason to use a template here in the first place, just make it a class with a non-static member and a decend constructor and you are done. Much simpler ...
+1  A: 

Why using 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 compiles mp to this on gcc-4.4.1 (I don't have access to MSVC at the moment):

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

It is just an offset to the member, which looks pretty compile-time to me.

With template, you need to specify the definition outside of 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));
}

Which compiles to:

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 smacks of standard library features reimplementation (see std::tr1::mem_fn).

Alex B
You just do not understand my question.
Alexey Malistov
Then please clarify your question, a lot of people seem to be in the same boat.
Alex B
Do not be offended. I want to save pointer to member in template class as a type or an integer. I need *a pointer to member traits* as type traits.
Alexey Malistov
That makes more sense now that you've mentioned this crucial bit.
Alex B
`template<int Foo::*Mem> int Foo::* const B<Mem>::mp = Mem;` is run-time solution. You define a new global variable `mp` and use it. Of course, it is possible there is an optimazation. But it is run-time solution, though.
Alexey Malistov
I accepted this solution. But I asked a new question about pointer to member http://stackoverflow.com/questions/1914342/is-there-pointer-to-member-traits-or-something-like-this .
Alexey Malistov