gcc 模板构造函数的显式示例化

hkmswyz6  于 2023-08-06  发布在  其他
关注(0)|答案(1)|浏览(104)

这个问题是来自Software Engineering Stack Exchange的migrated,因为它可以在Stack Overflow上回答。Migrated 8天前.
下面的代码:

#include <iostream>

class Test {
   public:
    Test() {std::cout << "I am called\n";};

    template <typename T>
    Test(T t);
};

template <typename T> Test::Test(T t){ std::cout << t << "\n";};

// Explicit template instantiation
template Test::Test<int>(int);
template Test::Test<double>(double);

int main() {
    Test test;
    Test test2(12342);
    Test test3(3.1415);
    return 0;
}

字符串
这段代码可以很好地与GCC(我的版本是13.2)一起编译和工作。输出如我所料:

I am called
12342
3.1415


Clang(我的版本是16.0.0)抛出错误,代码无法编译:

<source>:14:16: error: qualified reference to 'Test' is a constructor name rather than a type in this context
template Test::Test<int>(int);
               ^
<source>:14:20: error: expected unqualified-id
template Test::Test<int>(int);
                   ^
<source>:15:16: error: qualified reference to 'Test' is a constructor name rather than a type in this context
template Test::Test<double>(double);
               ^
<source>:15:20: error: expected unqualified-id
template Test::Test<double>(double);
                   ^
4 errors generated.


有人能帮助我理解这个问题或指导我找到来源吗?

pu3pd22g

pu3pd22g1#

模板参数列表不能按照[temp.arg.explicit]/1提供给构造函数,因为它要求函数专门化的模板参数列表遵循“function template name",而构造函数没有该参数列表。构造函数通过其包含类的 injected-class-name 命名,而不是像其他函数模板那样有一个名称。(构造函数只能以声明形式引用。例如,在写作时Test(1, 2)作为表达式,则Test引用类Test,而不是它的构造函数,不能显式命名或调用。
CWG 581的解决方案也重申了这一点,在2019年的C++20中,作为针对以前标准版本的缺陷报告,其措辞明确排除了[temp.arg.explicit]/2中构造函数的模板参数列表。
因此显式示例化不能有模板参数列表,但它也不需要。反而

template Test::Test(int);
template Test::Test(double);

字符串
就足够了。模板参数推导是在函数模板的显式示例化声明上完成的,因此这将选择预期的专门化。
这不是语言中的实际限制,因为不能以这种方式推导其模板参数的构造函数模板专门化将是无用的,因为它也永远不会被重载解析选择调用。构造函数也从不使用显式指定的模板参数调用。
GCC不应该接受没有诊断的代码。在CWG 581之前,意图可能并不完全清楚,但决议的措辞对我来说似乎非常清楚。GCC lists缺陷报告的实现为未知状态。Clang的行为是符合的。

相关问题