模板化 class 构造函数的模板实例化

Template instantiation of templated class constructor

这无法用 clang++ 编译,谁能解释为什么? (这用 g++ 编译得很好)

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

template X::X<int>();

int main() { return 1; }



instantiate.cc:7:13: error: qualified reference to 'X' is a constructor name rather than a type in this context
template X::X<int>();
            ^
instantiate.cc:7:14: error: expected unqualified-id
template X::X<int>();
             ^
2 errors generated.

我认为Clang是正确的。即使 Gcc 允许,也根本不能使用模板化构造函数。无法推导模板参数,也无法为构造函数模板显式指定模板参数。

[temp.arg.explicit]/2

Template arguments shall not be specified when referring to a specialization of a constructor template ([class.ctor], [class.qual]).

[temp.arg.explicit]/8

[ Note: Because the explicit template argument list follows the function template name, and because constructor templates ([class.ctor]) are named without using a function name ([class.qual]), there is no way to provide an explicit template argument list for these function templates. — end note ]

构造函数没有名字。正如 [class.ctor]/1 中所说的那样。它们是使用 class 的名称定义的特殊成员。但他们本身是无名的。虽然 C++ 允许我们在某些上下文中通过使用 class 名称来引用 c'tor,但这些是有限的。一般来说,我们不能说出一个c'tor。

这就是问题所在。要显式指定模板参数,我们必须使用模板化实体的名称。构造函数没有名称,因此我们无法明确指定它们的参数。

这是 [temp.arg.explicit] 中注释的主题,它总结了规范文本的意图。

7 [ Note: Because the explicit template argument list follows the function template name, and because conversion member function templates and constructor member function templates are called without using a function name, there is no way to provide an explicit template argument list for these function templates.  — end note ]

我们仍然可以实例化或特化构造函数,但前提是不必显式指定模板参数(如果它们是可推导的,或者来自默认模板参数)。例如

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

template X::X(int); // This will work

所以Clang拒绝你的代码并没有错。 GCC 可能会提供扩展。但最终,该标准没有提供一种方法来显式地向构造函数模板提供模板参数。


进一步挖掘后,有 CWG581,进一步确认 Clang 的行为是预期的。它似乎也进入了最新的标准修订版,对规范文本进行了一些更改。