为什么具有无效继承的类型在作为模板参数传递时不会被拒绝?

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()Tvoid(如您的情况)是 no-op,而 void_tdefined 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 并且编译器不应拒绝它。