考虑代码:
class Base{};
class Derived: public Base{};
template<Base& b> // references (and pointers) can be used as non-types
void f(){}
int main()
{
Derived d;
// f(d); // Error, template type must match exactly
f<(Base&)d>(); // Error here, why?!
}
我理解为什么注释调用失败:模板类型必须完全匹配。我在第二次调用中尝试使用强制转换,并得到此错误(gcc5.2):
错误:'d'不是类型'Base&amp;'的有效模板参数因为它不是具有外部链接的对象
如果我Derived d;
全局,则会出现同样的错误。 clang更有帮助,说
...注意:候选模板被忽略:显式指定无效 模板参数'b'的参数
我的问题是:上面的代码是否合法?如果没有,有什么理由吗?
答案 0 :(得分:4)
此答案假定为C ++ 11或更高版本
这里有两个问题:
1)非类型模板参数 [temp.arg.nontype] / p1
没有派生到基础的转换对于引用或指针类型的非类型模板参数, 常量表达式的值不应指(或指针类型,不得是地址):
- 子对象(1.8),
2)对象的地址应该在编译时可用。总结 [temp.arg.nontype] / p1 和 [expr.const] / p5 后,它应该有static storage duration。
将这两点放在一起,您将得到以下编译
class Base{};
class Derived: public Base{};
template<Base& b> // references (and pointers) can be used as non-types
void f(){}
Base obj; // Static storage duration
int main()
{
f<obj>();
}
答案 1 :(得分:2)
来自[temp.arg.nontype]:
非类型模板参数 的 template-argument 应为转换常量表达式(5.20) 模板参数的类型。
这里有两个问题。首先,d
没有链接,所以你不能在常量表达式中引用它。这是一个简单的解决方案:
Derived d;
int main() {
f<d>(); // still an error
}
现在,我们还有另一个问题。我们进入下一句话:
对于引用或指针类型的非类型模板参数, 常量表达式的值不应指(或指针类型,不应是地址):
(1.1) - 一个子对象(1.8),
我们试图将引用作为Derived
的子对象(基类子对象)。无论联系如何,都明确禁止这样做。