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

时间:2015-09-25 18:51:56

标签: c++ templates

考虑代码:

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'的参数

我的问题是:上面的代码是否合法?如果没有,有什么理由吗?

2 个答案:

答案 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>();
}

Live Example

答案 1 :(得分:2)

来自[temp.arg.nontype]:

  

非类型模板参数 template-argument 应为转换常量表达式(5.20)   模板参数的类型。

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

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

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

  

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

我们试图将引用作为Derived的子对象(基类子对象)。无论联系如何,都明确禁止这样做。