简体   繁体   中英

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

I saw 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?
};


While another answer said that the above example is valid C++. There are 2 sources for the claim that the above example is valid:

  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. In a CppCon conference Dan Saks basically showed a very similar example.

So as we can see the two linked answers make opposite claims and i don't know which one is correct. So my question is which of the two answers is correct. That is, is the declaration Stack<T>(); valid C++ or not.

PS: I am asking my question for Modern C++ meaning from C++11 & onwards.

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

Your example has an unqualified-id which is a template-id . This is not permitted under the latest wording , the constructor must be introduced by its injected-class-name .

Your quote about the equivalence between injected-class-name and template-name followed by template parameters doesn't apply here, because the identifier here isn't a type name, it is a constructor declaration.

This has definitely changed since C++11.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM