The shown snippet is valid for Pre-C++20 but not valid from C++20 & onwards as explained below.
Pre-C++20
From class.ctor#1.2:
1 -- Constructors do not have names. In a declaration of a constructor, the declarator is a function declarator of the form:
ptr-declarator ( parameter-declaration-clause ) noexcept-specifieropt attribute-specifier-seqopt
where the ptr-declarator consists solely of an id-expression, an optional attribute-specifier-seq, and optional surrounding parentheses, and the id-expression has one of the following forms:
1.2 -- in a member-declaration that belongs to the member-specification of a class template but is not a friend declaration, the id-expression is a class-name that names the current instantiation of the immediately-enclosing class template; or
(end quote)
This means that in C++17, we are allowed to use Stack<T>();
as the constructor declaration.
C++20
From class.ctor#1.1:
1 -- A constructor is introduced by a declaration whose declarator is a function declarator ([dcl.fct]) of the form:
ptr-declarator ( parameter-declaration-clause ) noexcept-specifieropt attribute-specifier-seqopt
where the ptr-declarator consists solely of an id-expression, an optional attribute-specifier-seq, and optional surrounding parentheses, and the id-expression has one of the following forms:
1.1 -- in a member-declaration that belongs to the member-specification of a class or class template but is not a friend declaration ([class.friend]), the id-expression is the injected-class-name ([class.pre]) of the immediately-enclosing entity or
So as we can see, the injected class name(which is Stack
and not Stack<T>
in your example) is needed for declaring the ctor of a class template.
This means that your given code is not valid for C++20.
The same is also mentioned at diff.cpp17.class#2:
Affected subclauses: [class.ctor] and [class.dtor]
Change: A simple-template-id is no longer valid as the declarator-id of a constructor or destructor.
Rationale: Remove potentially error-prone option for redundancy.
Effect on original feature: Valid C++ 2017 code may fail to compile in this revision of C++.
For example:
template<class T>
struct A {
A<T>(); // error: simple-template-id not allowed for constructor
A(int); // OK, injected-class-name used
~A<T>(); // error: simple-template-id not allowed for destructor
};