g ++和clang ++在struct / class specialization中使用非类型参数的不同行为

时间:2017-11-12 18:42:38

标签: c++ c++11 gcc clang template-specialization

我尝试理解14.5.5/8 of the C++11 standard的意义和含义(C++14中的同一性,我想,在C ++中17)

  

与专用非类型参数对应的模板参数的类型不应取决于特化的参数。

和往常一样,要了解g ++和clang ++之间的对应关系。

标准显示以下示例

template <class T, T t> struct C {};
template <class T> struct C<T, 1>; // error

并且g ++和clang ++都会出错。

到目前为止,非常好。

让我们复杂一点,添加一个类型的例子

template <typename, typename T, T>
struct foo { };

template <typename T>
struct foo<T, int, 1> { }; // compile

template <typename T>
struct foo<T, T, 1> { }; // error

g ++和clang ++都编译第一个部分特化(1int的类型,不是特化的参数),并给第二个({{{{{ 1}}是1,是专业化的参数)

到目前为止,非常好。

让我们介绍一个模板结构T,其内部类型依赖于模板参数

bar

以及以下计划

template <typename>
struct bar 
 { using type = int; };

它是在没有错误的情况下通过g ++编译的(在wandbox中使用4.9.3,5.5.0,7.2.0和头部8.0.0;使用c ++ 11,c ++ 14以及可用时,c ++ 17 )但clang ++(3.9.1,4.0.1,5.0.0,head 6.0.0; c ++ 11,c ++ 14,c ++ 17)给出以下错误

template <typename>
struct bar { using type = int; };

template <typename, typename T, T>
struct foo { };

template <typename T>
struct foo<T, typename bar<T>::type, 1> { };

int main ()
 { }
像往常一样:谁是对的?

clang ++,考虑prog.cc:11:38: error: non-type template argument specializes a template parameter with dependent type 'T' struct foo<T, typename bar<T>::type, 1> { }; ^ prog.cc:7:34: note: template parameter is declared here template <typename, typename T, T> ~^ 依赖于1(当T被修复为typename bar<T>::type时)或g ++不能减轻这种依赖性?

为了完整性,我不得不说如下更改int

bar

所以使template <typename T> struct bar { using type = T; }; 依赖于bar<T>::type,没有任何改变:g ++编译没有错误,而clang ++给出了同样的错误。

1 个答案:

答案 0 :(得分:2)

从编译器的角度来看它。

template <class T, T t> struct C {};
template <class T> struct C<T, 1>; // error

对于专业化,编译器不知道T是否确实具有值1,因此专业化无效。

有关

template <typename T>
struct foo<T, typename bar<T>::type, 1> { };

谁在说type总是int?您可能认为这很明显,但我可以针对一个特定的bar引入T的特化,以便typestd::string

template<>
struct bar<const volatile int> { using type = std::string };

基本上,您的声明“typename bar<T>::type被修复为int时出错了,它不是固定的。

现在怎样?这里的标准与第一个例子说的相同,专业化是不正确的,因为正如你的引用正确陈述的那样,非类型参数的类型取决于专业化的另一个(模板化)类型,即{{1这是未知的。在这方面,铿锵是对的,而gcc是错的。