如果我创建一个指向基类的成员,我通常可以将它转换为指向派生的成员,但不能在下面的Buzz模板中使用,其中第一个模板参数影响第二个模板参数。我是否在与编译器错误作斗争,或者标准真的要求这不起作用吗?
struct Foo
{
int x;
};
struct Bar : public Foo
{
};
template<class T, int T::* z>
struct Buzz
{
};
static int Bar::* const workaround = &Foo::x;
int main()
{
// This works. Downcasting of pointer to members in general is fine.
int Bar::* y = &Foo::x;
// But this doesn't, at least in G++ 4.2 or Sun C++ 5.9. Why not?
// Error: could not convert template argument '&Foo::x' to 'int Bar::*'
Buzz<Bar, &Foo::x> test;
// Sun C++ 5.9 accepts this but G++ doesn't because '&' can't appear in
// a constant expression
Buzz<Bar, static_cast<int Bar::*>(&Foo::x)> test;
// Sun C++ 5.9 accepts this as well, but G++ complains "workaround cannot
// appear in a constant expression"
Buzz<Bar, workaround> test;
return 0;
}
答案 0 :(得分:5)
根本不允许。根据§14.3.2/ 5:
对用作非类型模板参数的每个表达式执行以下转换。如果非类型模板参数无法转换为相应模板参数的类型,则程序格式不正确。
- 对于积分或枚举类型的非类型模板参数,应用积分促销(4.5)和积分转换(4.7)。
- 对于指向对象的类型指针的非类型模板参数,应用限定转换(4.4)和数组到指针转换(4.2)。 - 对于对象类型引用的非类型模板参数,不应用任何转换。引用引用的类型可能比模板参数的(否则相同)类型更符合cv。 template-parameter直接绑定到template-argument,该参数必须是左值 - 对于函数指针类型的非类型模板参数,仅应用函数到指针转换(4.3)。如果template-argument表示一组重载函数(或指向此类函数的指针),则从集合中选择匹配函数(13.4)。
- 对于函数类型引用的非类型模板参数,不适用任何转换。如果template-argument表示一组重载函数,则从集合中选择匹配函数(13.4) - 对于指向成员函数的类型指针的非类型模板参数,不应用任何转换。如果template-argument表示一组重载的成员函数,则从集合中选择匹配的成员函数(13.4) - 对于指向数据成员的类型指针的非类型模板参数,将应用限定转换(4.4)。
我强调了关于指向数据成员的指针的转换。请注意,未列出您的转换(§4.11/ 2)。在C ++ 0x中,它在这方面保持不变。