'Why don't types with invalid inheritance get rejected when passed as template parameters?

As we all know, classes can't be inherited from fundamental types and from classes that are marked as final. But despite that, the code presented below compiles without any problems on Clang 12 and GCC 9.

#include <type_traits>

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

int main()
{
    std::void_t<Inheriter<int>>();
}


Solution 1:[1]

There will only be an error due to the inheritance if the template specialization Inheriter<int> is instantiated.

Simply using the specialization, e.g. as a template argument, does not cause implicit instantiation. Roughly speaking implicit instantiation of the class template specialization happens only if it is used in a context that requires the class to be complete or otherwise depends on class completeness.

std::void_t is defined as

template<typename...>
using void_t = void;

There is nothing in this alias template that requires the template argument to be a complete type. As a consequence no implicit instantiation will happen.

The program is therefore well-formed and the compiler should not reject it.

Solution 2:[2]

Per [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

Meaning T() when T is void (as in your case) is a no-op, and void_t is defined as (per [temp.alias])

template<typename...> using void_t = void;

Meaning that if a valid type is supplied, then it will always become void.

Here's my take:

The code is syntactically correct, and if type substitution succeeds it is provably a no-op. Per the as-if rule, the compiler can prove that the program without this line altogether has identical runtime behavior, and therefore it is safe to ignore it completely. I can reproduce this behavior in MSVC, GCC, and Clang.

Solution 3:[3]

The compiler requires that the code be free of syntactic errors. And the sample snippet doesn't have any. Only when you create an Inheriter object can the compiler raise any errors (such as the ones you are expecting)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 user17732522
Solution 2 AndyG
Solution 3 GTA