考虑以下代码
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
};
看,如果此参数是typename或整数值,则可以保存任何模板参数。问题是指向成员的指针是一个偏移量,即整数。 现在我想在编译时保存任何指向成员的指针:
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。
注意。编译时间至关重要。请不要编写运行时解决方案。我知道。
答案 0 :(得分:2)
对于为什么'编译时很重要'(帮助建议替代方案)进行更详细的解释会更好。但是对于我的想法,你需要用指针到成员完成编译时间,你实际上可以做。我的变体是托马斯的建议与一些C ++的排序哲学相结合。首先让我们定义:
template <typename T, T v>
struct val
{};
这个struct模板可以有效地用作编译时间值,并且你不需要“static value = v;”,在编译或运行时使用它。考虑:
template <int n>
struct Foo
{
//something dependent on n
};
和
template <typename T>
struct Bar;
template <int n>
struct Bar <val <int, n> >
{
//something dependent of n
};
Foo和Bar功能相同,每个模板meta-kadabra都可以用Foo完成,也可以用Bar完成(只传递val而不是n)。您可以将指向成员的指针打包到val&lt;&gt;:
中val <typeof (&My::a), &My::a>
这些编译时间值现在可以存储在类型列表中(比如boost :: mpl :: something),比较,转换等等,一切都是编译时间。当你最终想要在运行时将它们用作指向成员的指针时,只需定义一个函数模板:
template <typename T, T value>
T
extract (val <T, value>)
{
return value;
}
并使用它:
typedef val <typeof (A::i), A::i> a_i;
A a;
std::cout << (a .* extract (a_i ()));
P.S。:关于这个解决方案有一些笨拙的结构,但这只是为了简单和解释。例如,相当丑陋(a。* extract(a_i()))可以通过将其包装成更具指针的成员来简化:
template <typename M, typename C>
typename mem_type <M>::value &
mem_apply (C &c)
{
M m;
return c .* extract (m);
}
其中mem_type是类模板,它提取由M引用的成员类型。然后用法为:
std::cout << mem_apply <a_i> (a);
答案 1 :(得分:1)
你不能。
但您可以使用functionoid代替。这个可以是一个编译时的解决方案。因为编译器可以内联,所以它甚至可能比指向成员函数的指针更快。例如:
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);
}
未经测试,但你明白了。
答案 2 :(得分:1)
为什么要使用模板?
#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;
}
以下在gcc-4.4.1上编译mp
(我目前无法访问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
)。
答案 3 :(得分:0)
您无法在结构定义中初始化静态成员。它需要像这样在外面声明(这可能不是你对模板的意图,但无论如何):
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));
}