有一个声明 Stack<T>();对于在 class 模板中有效的默认构造函数

Is having a declaration Stack<T>(); for the default ctor valid inside a class template

我看到了this answer to a question on SO related to the declaration for a default constructor of a class template that said that the following code is not valid C++ due to CWG1435:

template <class T> class Stack {
public:
  Stack<T>(); //IS THIS VALID?
};


而另一个 说上面的例子是有效的 C++。上述例子有效的说法有 2 个来源:

  1. Injected class names:

Otherwise, it is treated as a type-name, and is equivalent to the template-name followed by the template-parameters of the class template enclosed in <>

  1. CppCon conference Dan Saks 中基本上展示了一个非常相似的例子。

所以我们可以看到两个链接的答案提出了相反的说法,我不知道哪个是正确的。所以我的问题是两个答案中哪个是正确的。也就是说,声明 Stack<T>(); 是否有效 C++。

PS:我问的是现代 C++ 从 C++11 及以后的含义的问题。

您的示例有一个 unqualified-id,它是 template-idthe latest wording下不允许这样做,构造函数必须由其injected-class-name.

引入

您关于 injected-class-nametemplate-name 之间的等价性后跟模板参数的引用不适用这里,因为这里的标识符不是类型名称,所以它是构造函数声明。

自 C++11 以来,这肯定发生了变化。

显示的代码片段对 Pre-C++20 有效,但从 C++20 及以后的版本开始无效,如下所述。

Pre-C++20

来自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

(引用结束)

这意味着在C++17中,我们可以使用Stack<T>();作为构造函数声明。

C++20

来自 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

因此,正如我们所见,需要 注入的 class 名称 (在您的示例中是 Stack 而不是 Stack<T>)用于声明 class 模板的构造函数。

这意味着您给定的代码对 C++20 无效。


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
};