Рассмотрите следующий код
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
};
Посмотрите, возможно сохранить любой шаблонный параметр, если этот параметр является именем типа или целочисленным значением. Вещь состоит в том, что указатель на участника является смещением, т.е. целым числом. Теперь я хочу сохранить любой указатель на участника во время компиляции:
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));
}
Как сохранить указатель на участника во время компиляции? Я использую VS2008.
Примечание. Время компиляции очень важно. Не пишите решение во время выполнения. Я знаю это.
Зачем нужен шаблон?
#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;
}
Следующий код компилирует mp
на gcc-4.4.1 (в настоящий момент у меня нет доступа к MSVC):
.globl mp
.align 4
.type mp, @object
.size mp, 4
mp:
.long 4
Это просто смещение к члену, что для меня выглядит довольно неплохо во время компиляции.
В шаблоне вам нужно указать определение вне класса:
#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));
}
Который компилируется в:
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
Однако это все привкусы переопределения функций стандартной библиотеки (см. std :: tr1 :: mem_fn
).
Вы не можете.
Но вместо этого вы можете использовать функциональноид . Это может быть решением времени компиляции. А поскольку компилятор может встраивать вещи, он, возможно, даже быстрее, чем указатель на функцию-член. Пример:
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);
}
Не проверено, но идея вы поняли.
Вы не можете инициализировать статический член внутри определения структуры. Его нужно объявить снаружи следующим образом (что, вероятно, не то, что вы планировали с шаблоном, но в любом случае):
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));
}