g++ 和 clang++ 在 struct/class 专业化中使用非类型参数的不同行为
g++ and clang++ different behaviour with non-type argument in struct/class specialization
我试图理解 14.5.5/8 of the C++11 standard (idem in C++14 的含义和含义,我想,在 C++17 中)
The type of a template parameter corresponding to a specialized non-type argument shall not be dependent on a parameter of the specialization.
并且像往常一样,了解 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++ 都编译了第一个部分特化(1
、int
的类型不是特化的参数)并给出了第二个部分的错误(1
、int
的类型1
是 T
,特化的一个参数)
到目前为止,还不错。
让我们引入一个模板结构bar
,其内部类型不依赖于模板参数
template <typename>
struct bar
{ using type = int; };
和以下程序
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 ()
{ }
它由 g++ 编译,没有错误(在 4.9.3、5.5.0、7.2.0 和 head 8.0.0 的 wandbox 中试过;用 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) 给出以下错误
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>
~^
像往常一样:谁是对的?
clang++,认为 1
依赖于 T
(当 typename bar<T>::type
固定为 int
时)或 g++ 不解除这种依赖?
为了完整起见,我不得不说更改 bar
如下
template <typename T>
struct bar { using type = T; };
所以让 bar<T>::type
依赖于 T
,没有任何变化:g++ 编译没有错误,而 clang++ 给出了同样的错误。
从编译器的角度来看。
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
?您可能认为这很明显,但我可以为一个特定的 T
引入 bar
的特化,这样 type
就是 std::string
:
template<>
struct bar<const volatile int> { using type = std::string };
基本上,你的说法“当typename bar<T>::type
被固定为int
”是错误的,它没有固定。
现在呢?这里的标准与您的第一个示例所说的相同,专业化格式错误,因为正如您的引述正确指出的那样,非类型参数的类型取决于专业化的另一个(模板化)类型,即 T
,这是未知的。在这方面,clang 是对的,而 gcc 是错的。
我试图理解 14.5.5/8 of the C++11 standard (idem in C++14 的含义和含义,我想,在 C++17 中)
The type of a template parameter corresponding to a specialized non-type argument shall not be dependent on a parameter of the specialization.
并且像往常一样,了解 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++ 都编译了第一个部分特化(1
、int
的类型不是特化的参数)并给出了第二个部分的错误(1
、int
的类型1
是 T
,特化的一个参数)
到目前为止,还不错。
让我们引入一个模板结构bar
,其内部类型不依赖于模板参数
template <typename>
struct bar
{ using type = int; };
和以下程序
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 ()
{ }
它由 g++ 编译,没有错误(在 4.9.3、5.5.0、7.2.0 和 head 8.0.0 的 wandbox 中试过;用 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) 给出以下错误
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>
~^
像往常一样:谁是对的?
clang++,认为 1
依赖于 T
(当 typename bar<T>::type
固定为 int
时)或 g++ 不解除这种依赖?
为了完整起见,我不得不说更改 bar
如下
template <typename T>
struct bar { using type = T; };
所以让 bar<T>::type
依赖于 T
,没有任何变化:g++ 编译没有错误,而 clang++ 给出了同样的错误。
从编译器的角度来看。
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
?您可能认为这很明显,但我可以为一个特定的 T
引入 bar
的特化,这样 type
就是 std::string
:
template<>
struct bar<const volatile int> { using type = std::string };
基本上,你的说法“当typename bar<T>::type
被固定为int
”是错误的,它没有固定。
现在呢?这里的标准与您的第一个示例所说的相同,专业化格式错误,因为正如您的引述正确指出的那样,非类型参数的类型取决于专业化的另一个(模板化)类型,即 T
,这是未知的。在这方面,clang 是对的,而 gcc 是错的。