Variadic template template wrapper:奇怪的编译器错误,可能是错误
Variadic template template wrapper: weird compilers errors, possibly bugs
在多年的模板元编程实践中,我遇到过各种奇怪的编译器错误和错误。但是对于这个,我必须说我有些困惑。我不知道哪个编译器是正确的:gcc
、clang
、msvc
和 intel
都给出了不同的结果(听起来可能令人惊讶,只有 intel
编译代码没有错误)。更令人惊讶的是,它不依赖任何新的 C++
功能,因为只涉及 C++11
。
代码本身会说话,因为它相对简单。它仅包含一个可变参数模板模板包装器和一个可变参数内部实体,该实体可以是结构或别名模板。无论出于何种原因,别名模板版本 returns 在构造它的实例时对某些编译器来说是一个错误:
#include <type_traits>
template <class T1, class T2, class T3>
struct ternary {};
template <template <class...> class Template, class... Types>
struct template_struct {
template <class... Args>
struct type: Template<Types..., Args...> {};
};
template <template <class...> class Template, class... Types>
struct template_alias {
template <class... Args>
using type = Template<Types..., Args...>;
};
现在测试:
int main(int, char**) {
using ts0 = template_struct<ternary>; // OK
using ts1 = template_struct<ternary, bool>; // OK
using ts2 = template_struct<ternary, bool, char>; // OK
using ts3 = template_struct<ternary, bool, char, int>; // OK
using ts4 = template_struct<ternary, bool, char, int, double>; // OK
ts0 s0; // OK
ts1 s1; // OK
ts2 s2; // OK
ts3 s3; // OK
ts4 s4; // OK
using ta0 = template_alias<ternary>; // OK
using ta1 = template_alias<ternary, bool>; // OK
using ta2 = template_alias<ternary, bool, char>; // OK
using ta3 = template_alias<ternary, bool, char, int>; // OK
using ta4 = template_alias<ternary, bool, char, int, double>; // OK
ta0 a0; // OK
ta1 a1; // OK
ta2 a2; // OK
ta3 a3; // GCC, INTEL => OK | CLANG, MSVC => ERROR: WAIT WHAT ?!?!
ta4 a4; // INTEL => OK | GCC, CLANG, MSVC => ERROR
return 0;
}
代码在编译器资源管理器上可用:https://godbolt.org/z/3ndYMWvfs
问题:发生了什么事?哪个编译器是正确的?标准怎么说?是编译器错误吗?
所有编译器都是正确的,两个失败的测试是 ill-formed NDR(“不需要诊断”)。
> 3
参数案例是 ill-formed NDR 因为 [temp.res.general]/6.1
:
The program is ill-formed, no diagnostic required, if:
— no valid specialization can be generated for a template ... and the template is not instantiated, ...
== 3
参数案例是 ill-formed NDR 因为 [temp.res.general]/6.3
:
The program is ill-formed, no diagnostic required, if:
— every valid specialization of a variadic template requires an empty template parameter pack ...
这两个 template_struct<ternary, ...>
测试似乎是合法的,因为您可以将 struct type
特化为有效的东西,而且我没有立即看到必须至少有一个有效特化的规则主要(非专用)模板。
在多年的模板元编程实践中,我遇到过各种奇怪的编译器错误和错误。但是对于这个,我必须说我有些困惑。我不知道哪个编译器是正确的:gcc
、clang
、msvc
和 intel
都给出了不同的结果(听起来可能令人惊讶,只有 intel
编译代码没有错误)。更令人惊讶的是,它不依赖任何新的 C++
功能,因为只涉及 C++11
。
代码本身会说话,因为它相对简单。它仅包含一个可变参数模板模板包装器和一个可变参数内部实体,该实体可以是结构或别名模板。无论出于何种原因,别名模板版本 returns 在构造它的实例时对某些编译器来说是一个错误:
#include <type_traits>
template <class T1, class T2, class T3>
struct ternary {};
template <template <class...> class Template, class... Types>
struct template_struct {
template <class... Args>
struct type: Template<Types..., Args...> {};
};
template <template <class...> class Template, class... Types>
struct template_alias {
template <class... Args>
using type = Template<Types..., Args...>;
};
现在测试:
int main(int, char**) {
using ts0 = template_struct<ternary>; // OK
using ts1 = template_struct<ternary, bool>; // OK
using ts2 = template_struct<ternary, bool, char>; // OK
using ts3 = template_struct<ternary, bool, char, int>; // OK
using ts4 = template_struct<ternary, bool, char, int, double>; // OK
ts0 s0; // OK
ts1 s1; // OK
ts2 s2; // OK
ts3 s3; // OK
ts4 s4; // OK
using ta0 = template_alias<ternary>; // OK
using ta1 = template_alias<ternary, bool>; // OK
using ta2 = template_alias<ternary, bool, char>; // OK
using ta3 = template_alias<ternary, bool, char, int>; // OK
using ta4 = template_alias<ternary, bool, char, int, double>; // OK
ta0 a0; // OK
ta1 a1; // OK
ta2 a2; // OK
ta3 a3; // GCC, INTEL => OK | CLANG, MSVC => ERROR: WAIT WHAT ?!?!
ta4 a4; // INTEL => OK | GCC, CLANG, MSVC => ERROR
return 0;
}
代码在编译器资源管理器上可用:https://godbolt.org/z/3ndYMWvfs
问题:发生了什么事?哪个编译器是正确的?标准怎么说?是编译器错误吗?
所有编译器都是正确的,两个失败的测试是 ill-formed NDR(“不需要诊断”)。
> 3
参数案例是 ill-formed NDR 因为 [temp.res.general]/6.1
:
The program is ill-formed, no diagnostic required, if:
— no valid specialization can be generated for a template ... and the template is not instantiated, ...
== 3
参数案例是 ill-formed NDR 因为 [temp.res.general]/6.3
:
The program is ill-formed, no diagnostic required, if:
— every valid specialization of a variadic template requires an empty template parameter pack ...
这两个 template_struct<ternary, ...>
测试似乎是合法的,因为您可以将 struct type
特化为有效的东西,而且我没有立即看到必须至少有一个有效特化的规则主要(非专用)模板。