显式转换模板非类型参数时出错

Error when explicitly converting a template non-type parameter

本文关键字:出错 类型参数 显式转换      更新时间:2023-10-16

考虑以下代码:

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&'类型的有效模板参数,因为它不是具有外部链接的对象

如果我使Derived d;全局相同的错误。Clang更有帮助,它说

…注意:候选模板被忽略:无效的显式指定模板形参'b'的实参

我的问题是:上面的代码是否合法?如果不是,有什么原因吗?

此答案假设c++ 11或更高版本

有两个问题:

1)非类型模板形参[temp.arg.nontype]/p1

对于引用类型或指针类型的非类型模板形参常量表达式的值不能指向(或者对于指针类型,不能是的地址):

-子对象(1.8),

2)对象的地址在编译时应该是可用的。总结(temp.arg 。Nontype]/p1 and [expr。Const]/p5因此,它应该具有静态存储时间。

把这两点放在一起,你会得到下面的编译

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>();
}
<<p> 生活例子/kbd>

From [temp.arg.nontype]:

对于非类型的模板形参模板实参必须是的转换后的常量表达式 (5.20)模板参数的类型。

这里有两个问题。首先,d没有链接,所以你不能在常量表达式中引用它。这是一个简单的修复:

Derived d;
int main() {
    f<d>(); // still an error
}

现在,我们有另一个问题。我们进入下一个句子:

对于引用类型或指针类型的非类型模板参数常量表达式的值不能指向(或者对于指针类型,不能是的地址):
(1.1) -子对象(1.8),

我们试图将引用作为Derived的子对象(基类子对象)。无论链接如何,这都是不允许的。