为什么具有无效继承的类型在作为模板参数传递时不会被拒绝?
Why don't types with invalid inheritance get rejected when passed as template parameters?
众所周知,类 不能从基本类型和标记为 final
的 类 继承。但是尽管如此,下面显示的代码在 Clang 12 和 GCC 9 上编译没有任何问题。
#include <type_traits>
template<typename T>
struct Inheriter : public T{};
int main()
{
std::void_t<Inheriter<int>>();
}
编译器要求代码没有语法错误。示例片段没有任何内容。只有当您创建一个 Inheriter
对象时,编译器才能引发任何错误(例如您期望的错误)
根据 [expr.type.conv]:
If the initializer is a parenthesized single expression, the type conversion expression is equivalent to the corresponding cast expression. Otherwise, if the type is cv void and the initializer is () or {} (after pack expansion, if any), the expression is a prvalue of type void that performs no initialization
意思是 T()
当 T
是 void
(如您的情况)是 no-op,而 void_t
是 defined as(每 [temp.alias])
template<typename...> using void_t = void;
意味着如果提供了一个有效的类型,那么它总是会变成void
。
这是我的看法:
该代码在语法上是正确的,如果类型替换成功,则可以证明它是 no-op。根据 as-if rule,编译器可以证明没有这一行的程序完全具有相同的运行时行为,因此完全忽略它是安全的。我可以在 MSVC、GCC 和 Clang 中重现此行为。
如果模板特化Inheriter<int>
是实例化.
,只有继承才会出错
简单地使用专业化,例如作为模板参数,不会导致隐式实例化。粗略地说,只有在需要 class 完整或依赖于 class 完整性的上下文中使用时,才会发生 class 模板特化的隐式实例化。
std::void_t
定义为
template<typename...>
using void_t = void;
此别名模板中没有任何内容要求模板参数为完整类型。因此,不会发生隐式实例化。
因此该程序 well-formed 并且编译器不应拒绝它。
众所周知,类 不能从基本类型和标记为 final
的 类 继承。但是尽管如此,下面显示的代码在 Clang 12 和 GCC 9 上编译没有任何问题。
#include <type_traits>
template<typename T>
struct Inheriter : public T{};
int main()
{
std::void_t<Inheriter<int>>();
}
编译器要求代码没有语法错误。示例片段没有任何内容。只有当您创建一个 Inheriter
对象时,编译器才能引发任何错误(例如您期望的错误)
根据 [expr.type.conv]:
If the initializer is a parenthesized single expression, the type conversion expression is equivalent to the corresponding cast expression. Otherwise, if the type is cv void and the initializer is () or {} (after pack expansion, if any), the expression is a prvalue of type void that performs no initialization
意思是 T()
当 T
是 void
(如您的情况)是 no-op,而 void_t
是 defined as(每 [temp.alias])
template<typename...> using void_t = void;
意味着如果提供了一个有效的类型,那么它总是会变成void
。
这是我的看法:
该代码在语法上是正确的,如果类型替换成功,则可以证明它是 no-op。根据 as-if rule,编译器可以证明没有这一行的程序完全具有相同的运行时行为,因此完全忽略它是安全的。我可以在 MSVC、GCC 和 Clang 中重现此行为。
如果模板特化Inheriter<int>
是实例化.
简单地使用专业化,例如作为模板参数,不会导致隐式实例化。粗略地说,只有在需要 class 完整或依赖于 class 完整性的上下文中使用时,才会发生 class 模板特化的隐式实例化。
std::void_t
定义为
template<typename...>
using void_t = void;
此别名模板中没有任何内容要求模板参数为完整类型。因此,不会发生隐式实例化。
因此该程序 well-formed 并且编译器不应拒绝它。