为什么只有有效的空可变参数包的模板格式错误?
Why template with only valid empty variadic pack ill formed?
理由是什么
(8) The validity of a template may be checked prior to any instantiation. [ Note: Knowing which names are type names allows the syntax of every template to be checked in this way. — end note ] The program is ill-formed, no diagnostic required, if:
[..]
(8.3) every valid specialization of a variadic template requires an empty template parameter pack, or
该规则不允许如下技巧强制模板推导为:
template <typename ...Ts,
typename A,
typename B,
std::enable_if_t<sizeof...(Ts) == 0, int> = 0> // Ill-formed NDR :-(
Pair<std::decay_t<A>, std::decay_t<B>> MakePair(A&&a, B&& b)
{
return {a, b};
}
注意:我知道 C++17 推导规则使 make_*
过时。
一般来说,实现可以及早诊断出模板中的明显错误,因为无论如何您都无法生成有效的实例化。但是包扩展有点独特,因为整个构造在实例化时可以消失。因此,需要该规则来禁止在包装扩展的事物中出现各种明显的自负,并允许对它们进行早期诊断:
template<class...Ts>
union U : Ts... {}; // unions can't have base classes
template<class...Ts>
class C : Ts..., Ts... {}; // classes can't have duplicate direct base classes
template<class...Ts>
void f() {
// sizeof(void) is invalid, but it can vanish
int x[] = {(sizeof(void) + sizeof(Ts))..., 0};
}
这对编译器实现者也有一定的帮助,因为他们对模板的内部表示不需要支持这些废话。
理由是什么
(8) The validity of a template may be checked prior to any instantiation. [ Note: Knowing which names are type names allows the syntax of every template to be checked in this way. — end note ] The program is ill-formed, no diagnostic required, if:
[..]
(8.3) every valid specialization of a variadic template requires an empty template parameter pack, or
该规则不允许如下技巧强制模板推导为:
template <typename ...Ts,
typename A,
typename B,
std::enable_if_t<sizeof...(Ts) == 0, int> = 0> // Ill-formed NDR :-(
Pair<std::decay_t<A>, std::decay_t<B>> MakePair(A&&a, B&& b)
{
return {a, b};
}
注意:我知道 C++17 推导规则使 make_*
过时。
一般来说,实现可以及早诊断出模板中的明显错误,因为无论如何您都无法生成有效的实例化。但是包扩展有点独特,因为整个构造在实例化时可以消失。因此,需要该规则来禁止在包装扩展的事物中出现各种明显的自负,并允许对它们进行早期诊断:
template<class...Ts>
union U : Ts... {}; // unions can't have base classes
template<class...Ts>
class C : Ts..., Ts... {}; // classes can't have duplicate direct base classes
template<class...Ts>
void f() {
// sizeof(void) is invalid, but it can vanish
int x[] = {(sizeof(void) + sizeof(Ts))..., 0};
}
这对编译器实现者也有一定的帮助,因为他们对模板的内部表示不需要支持这些废话。