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

i c*_*ant 8 c++ metaprogramming template-meta-programming

众所周知,类不能从基本类型和标记为 的类继承final。但尽管如此,下面提供的代码在 Clang 12 和 GCC 9 上编译时没有任何问题。

#include <type_traits>

template<typename T>
struct Inheriter : public T{};

int main()
{
    std::void_t<Inheriter<int>>();
}
Run Code Online (Sandbox Code Playgroud)

And*_*dyG 6

根据[expr.type.conv]

如果初始值设定项是带括号的单个表达式,则类型转换表达式等效于相应的强制转换表达式。否则,如果类型为 cv void 并且初始值设定项为 () 或 {}(在包扩展之后,如果有),则表达式是 void 类型的纯右值,不执行初始化

意味着T()何时(如您的情况)Tvoid无操作,并且void_t定义(per [temp.alias])

template<typename...> using void_t = void;
Run Code Online (Sandbox Code Playgroud)

这意味着如果提供了有效类型,那么它将始终变为void.

这是我的看法:

该代码在语法上是正确的,如果类型替换成功,则可以证明它是一个无操作。根据as-if 规则,编译器可以证明没有此行的程序完全具有相同的运行时行为,因此可以安全地完全忽略它。我可以在 MSVC、GCC 和 Clang 中重现此行为。


use*_*522 5

Inheriter<int>如果实例化模板化,则只会因继承而出现错误。

简单地使用特化(例如作为模板参数)不会导致隐式实例化。粗略地说,类模板特化的隐式实例化仅在需要类完整或依赖于类完整性的上下文中使用时才会发生。

std::void_t定义为

template<typename...>
using void_t = void;
Run Code Online (Sandbox Code Playgroud)

此别名模板中没有任何内容要求模板参数是完整类型。因此,不会发生隐式实例化。

因此,该程序是格式良好的,编译器不应拒绝它。