为什么在指定具有其所有模板参数的默认值的模板类时需要<>?

Dan*_*nra 7 c++ templates c++17

<>在指定具有其所有模板参数的默认值的模板类时,是否有必要说明原因?

例如

#include <iostream>

template<typename T = int>
class C {
public:
    T obj = 0;
};

int main()
{
    C c1; // Error on almost all compilers (see note below)
    C<> c2;
    std::cout << c1.obj << " " << c2.obj << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这样做的一个示例缺点是,如果您有一个已在各个地方使用的类,并且您稍后将其重构为具有其模板参数的默认参数的类模板,那么您必须添加<>所有使用该模板参数的地方类.

注意:看起来GCC最新的HEAD(7.0.1)不接受语法<>.早期版本没有,也没有任何版本的Clang.这是最新的GCC HEAD中的错误吗?或者也许C++ 17的标准现在接受语法而没有<>GCC就在这里?

Bar*_*rry 4

在 C++17 中,这是格式良好的:

C c1{};
Run Code Online (Sandbox Code Playgroud)

由于类模板的扣除。我们为每个构造函数(和推导指南)合成一个函数并执行重载决策:

template <class T=int> C<T> foo();
template <class T=int> C<T> foo(C<T> const&);
template <class T=int> C<T> foo(C<T>&&);
Run Code Online (Sandbox Code Playgroud)

第一个是可行的重载,其他两个不是,因此推导成功,占位符C被推导的类型替换C<int>。

然而,从语法上来说,[dcl.type.class.deduct] 中需要一个初始化器:

如果推导类类型的占位符在simple-declaration的decl-specifier-seq中显示为decl-specifier,则该声明的init-declarator应采用以下形式:

声明符-id 属性说明符-seq opt 初始值设定项

占位符被替换为类模板推导的重载决策所选择的函数的返回类型 (13.3.1.8)。

但C c;不包含初始值设定项,因此它在语法上不符合。这是允许这样做的 gcc 错误。尽管明确禁止这样做似乎很奇怪。显然,这个限制在 Kona 中已经取消,因此C c;在 C++17 中确实是格式良好的。一旦有新的措辞出现,我将更新答案。


在 C++17 之前,该语句的格式不正确,只是因为C不是类型。C和C<>不是同一件事。过去和现在都没有对所有默认模板参数进行特殊考虑。类型和类模板是不同的,并且继续以不同的方式对待。

  • @Danra 显然,上周在 Kona 取消了初始化程序限制,因此 `C c;` 确实有效。 (3认同)