类模板构造函数在c ++ 20中可以有一个冗余的模板参数列表吗

据我所知,以下代码:

template<typename T>
struct S {
    S<T>();
};

是格式良好的,即使构造函数声明中的 是多余的.

is well-formed, even though the <T> in the declaration of the constructor is redundant.

但是,在 gcc 主干上(但不是在 gcc10.2 上),使用 -std=c++20 会出现错误:

However, on gcc trunk (but not on gcc10.2), with -std=c++20 this gives an error:

error: expected unqualified-id before ')' token
    3 |     S<T>();
                 ^

代码使用-std=c++20.这是一个错误,还是 C++20 中尚未在所有编译器中实现的重大更改?

The code compiles on clang trunk with -std=c++20. Is this a bug, or is this a breaking change in c++20 that is yet to be implemented in all compilers?

推荐答案

事实上发生了变化.它记录在 C++20 草案的兼容性部分.

There was a change, in fact. It's documented in the compatibility section of the C++20 draft.

[diff.cpp17.class]

2 受影响的子条款:[class.ctor] 和 [class.dtor]
更改:简单模板 ID 不再作为构造函数或析构函数的声明符 ID 有效.
基本原理:删除可能容易出错的冗余选项.
对原始特性的影响:有效的 C++ 2017 代码可??能无法在此国际标准中编译.例如:

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 International Standard. 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
};

具体来说,措辞delta是这样的:

Specifically, the wording delta is this:

n4659 - C++17 标准草案 - [class.ctor]

n4659 - C++17 standard draft - [class.ctor]

1 构造函数没有名称.在构造函数的声明中,声明符是形式为

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-specifier attribute-specifier-seq

其中 ptr-declarator 仅由 id-expression、可选的属性说明符-seq 和可选的括号组成,并且 id-expression 具有以下形式之一:

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:

  • 在属于类的成员规范但不是友元声明的成员声明中,id-expression 是直接封闭类的注入类名;
  • 在属于类模板的成员规范但不是友元声明的成员声明中,id 表达式是命名当前实例化的类名立即封闭的类模板;或

n4861 - C++20 标准草案 - [class.ctor]

n4861 - C++20 standard draft - [class.ctor]

1 构造函数由其声明符的声明引入是一个形式的函数声明符 ([dcl.fct])

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-specifier attribute-specifier-seq

其中 ptr 声明符仅由一个 id 表达式组成,一个可选的属性说明符序列和可选的环绕括号,并且 id 表达式具有以下形式之一:

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:

  • 在属于类或类模板的成员规范但不是友元声明的成员声明中([class.friend]),id-expression 是注入的类名([class.pre]) 的直接封闭实体或

如您所见,措辞发生了变化.C++20 现在在声明类模板的构造函数时需要注入的类名.S<T> 是一个简单的模板 id,用于命名专业化.在模板中,注入的类名只是S.

As you can see, the wording changed. C++20 now requires the injected class name when declaring a constructor for a class template. S<T> is a simple template id that names a specialization. Inside a template, the injected class name is simply S.

这是解决 CWG 2237.

相关文章