为什么在别名声明中无效替换 class 模板派生模板参数不会导致错误

why was invalid substitution of class template deriving template arguments in alias declaration not resulting in error

我已经测试了这几个模板来证明模板实例化的有效性:

template <typename T>
using LRef = T&;

template <typename T>
using Ptr = T*;

template <typename>
  requires false
class A {};

// ...

using T0 = LRef<int>;  // expected ok
// using T1 = LRef<void>; // expected error, forming void& which is invalid
using T2 = Ptr<void>;  // expected ok
// using T3 = Ptr<int&>;  // expected error, forming int& * which is invalid
// using T4 = A<int>;     // expected error, unsatisfied constraint resulting in invalid instantiation

然而,

template <typename T>
struct Box { T value; };

template <typename T, typename U = T>
struct Derive : T, U {};

// ...
using T5 = Derive<int, float>; // unexpected no-error, but should be invalid
// template struct Derive<int, float>; // expected error

using T6 = Derive<Box<int>, Box<float>>; // expected ok
template struct Derive<Box<int>, Box<float>>; // expected ok

using T7 = Derive<Box<int>>; // unexpected no-error, but should be invalid
// template struct Derive<Box<int>>; // expected error

void foo() {
    // T5 {}; // error
    // T7 {}; // error
}

T5T7 的类型别名声明没有错误,这是意外的。我想它们应该是无效的,因为使用相同模板参数的显式实例化和类型别名的使用有错误。

这是标准 C++ 中的正确行为还是只是未正确实现?这 3 个主要编译器(GCC、Clang 和 MSVC)显示此程序没有编译错误。 https://godbolt.org/z/hcbszo49a

Is this valid in standard C++ or just not implemented properly?

不使用T5{};T7{};second snippet是well-formed。

这是因为typedefs,using并不需要完全定义类型。从 implicit instantiation's documentation:

When code refers to a template in context that requires a completely defined type, or when the completeness of the type affects the code, and this particular type has not been explicitly instantiated, implicit instantiation occurs. For example, when an object of this type is constructed, but not when a pointer to this type is constructed.

(强调我的)

并且由于 type alias 不需要完全定义的类型,根据上面引用的语句,typedef 或 [= 不会有隐式实例化14=].

例如:

template<typename T> struct C{ T& k;};
using V = C<void>; //no implicit instantiation
int main()
{
    C<int>* k;//no implicit instantiation
    C<void>* l; //no implicit instantiation
   
};

Demo


They should be invalid since the explicit instantiation with the same template arguments and the usage of type alias has errors.

请注意,在您使用 别名模板 而不是 class 模板的第一个片段中,所有编译器似乎都会产生错误(Demo) you mentioned but this is because they are allowed(but not required) to do so as also explained in .