有一个声明 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 个来源:
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 <>
- 在 CppCon conference Dan Saks 中基本上展示了一个非常相似的例子。
所以我们可以看到两个链接的答案提出了相反的说法,我不知道哪个是正确的。所以我的问题是两个答案中哪个是正确的。也就是说,声明 Stack<T>();
是否有效 C++。
PS:我问的是现代 C++ 从 C++11 及以后的含义的问题。
您的示例有一个 unqualified-id,它是 template-id。 the latest wording下不允许这样做,构造函数必须由其injected-class-name.
引入
您关于 injected-class-name 和 template-name 之间的等价性后跟模板参数的引用不适用这里,因为这里的标识符不是类型名称,所以它是构造函数声明。
自 C++11 以来,这肯定发生了变化。
显示的代码片段对 Pre-C++20 有效,但从 C++20 及以后的版本开始无效,如下所述。
Pre-C++20
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 无效。
也提到了同样的内容
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
};
我看到了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?
};
而另一个
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 <>
- 在 CppCon conference Dan Saks 中基本上展示了一个非常相似的例子。
所以我们可以看到两个链接的答案提出了相反的说法,我不知道哪个是正确的。所以我的问题是两个答案中哪个是正确的。也就是说,声明 Stack<T>();
是否有效 C++。
PS:我问的是现代 C++ 从 C++11 及以后的含义的问题。
您的示例有一个 unqualified-id,它是 template-id。 the latest wording下不允许这样做,构造函数必须由其injected-class-name.
引入您关于 injected-class-name 和 template-name 之间的等价性后跟模板参数的引用不适用这里,因为这里的标识符不是类型名称,所以它是构造函数声明。
自 C++11 以来,这肯定发生了变化。
显示的代码片段对 Pre-C++20 有效,但从 C++20 及以后的版本开始无效,如下所述。
Pre-C++20
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 无效。
也提到了同样的内容
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 };