vuk*_*ung 7 c++ gcc templates instantiation clang++
看起来Clang(3.8)和GNU C++(4.9)中模板实例化的规则是不一样的.这是一个例子:
#include <cstddef>
template <bool>
class Assert {
Assert(); // private constructor for Assert<false>
};
template <>
class Assert<true> { // implicit public constructor for Assert<true>
};
template <size_t N>
class A {
};
template <class T, size_t N>
T foo(A<N>) {
return T(N - 1);
}
template <class T>
T foo(A<0>) { // foo is not defined for N=0
Assert<false>();
return T(0);
}
int main(int argc, char **argv) {
foo<int>(A<3>());
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这个最小的例子显示了一个模板函数,foo它是在一个类型T和一个自然数上推广的N.此函数未定义N=0,因此Assert如果以这种方式使用,我想使用该类来表示编译器错误.
这段代码被GNU编译器(以及Visual C++ 2015)接受,但Clang给出了"调用类的私有构造函数"的错误Assert<false>.
那么谁是对的?在我看来,没有要求foo<T,0>,所以没有必要实例化这个模板......
编辑:接受Clang对标准的解释,对模板参数执行编译时检查的规范方法是什么?
我相信铿锵是正确的,因为Assert<false>它不是一种依赖类型.
http://en.cppreference.com/w/cpp/language/dependent_name
在模板定义点查找并绑定非依赖名称.即使在模板实例化时存在更好的匹配,此绑定也成立:
不要使专业化无效.使它们成为通用目的并使用static_assert(带有依赖值)来检查无效的模板参数类型/值. static_assert(std::is_same<T, int>::value)要么static_assert(N != 0)
接受Clang对标准的解释,对模板参数执行编译时检查的规范方法是什么?
您可以删除foo()for 的"specialization"/重载A<0>并定义常规模板,如下所示:
template <class T, size_t N>
T foo(A<N>) {
Assert<N != 0>();
return T(N - 1);
}
Run Code Online (Sandbox Code Playgroud)
使用C++ 11,您无需定义自己的静态Assert,并且可以使用提供的语言static_assert:
template <class T, size_t N>
T foo(A<N>) {
static_assert(N!=0, "N must be positive");
return T(N - 1);
}
Run Code Online (Sandbox Code Playgroud)
两个编译器都是正确的.像往常一样,这是由[temp.res]/8控制的:
知道哪些名称是类型名称允许检查每个模板的语法.如果出现以下情况,该计划格式错误,无需诊断:
无法为模板中的模板或子
constexpr if语句([stmt.if])生成有效的专门化,并且模板未实例化,或者可变参数模板的每个有效特化都需要一个空的模板参数包,或
由于不依赖于模板参数的构造,或者在其定义之后立即对模板进行假设实例化将是不正确的,或者
在假设实例中对这种构造的解释不同于在模板的任何实际实例化中对相应构造的解释.
您的模板与第三个要点发生冲突.
至于正确的解决方案,可以使用合适的解决方案,也static_assert可以明确删除不需要的重载:
template <class T>
T foo(A<0>) = delete;
Run Code Online (Sandbox Code Playgroud)
前者允许更好的错误消息,后者与其他元编程更好地发挥作用.
| 归档时间: |
|
| 查看次数: |
628 次 |
| 最近记录: |