通过一个类似的问题(链接),我感到惊讶(和困惑)。我自己尝试了这个问题中提到的标准示例:
template <typename T, typename U = int> struct S;
template <typename T = int, typename U> struct S
{ void f() { std::cout << __PRETTY_FUNCTION__ << '\n'; } };
int main()
{
S s; s.f();
return 0;
}
上面的代码输出
void S<int, int>::f() [T = int, U = int]
。使用gcc HEAD 8.0.1 201803编译可以通过,但使用clang HEAD 7.0.0编译会失败,除非在实例化时使用尖括号。请参考gcc编译结果和clang编译结果。S s; s.f(); // error: declaration of variable 's' with deduced type 'S' requires an initializer
S<> t; t.f(); // Correct
不考虑这个问题,我已经检查了其他模板样式来验证它们的行为方式。代码被接受或拒绝的方式非常不规则。
模板函数
template <typename T, typename U = int> void function();
template <typename T = int, typename U> void function()
{ std::cout << __PRETTY_FUNCTION__ << '\n'; }
int main()
{
/* Rejected by GCC: no matching function for call to 'function()'
template argument deduction/substitution failed:
couldn't deduce template parameter 'T'
same error with function<>()
CLang compiles without issues */
function(); // CLang prints 'void function() [T = int, U = int]'
return 0;
}
模板变量
template <typename T, typename U = int> int variable;
template <typename T = int, typename U> int variable = 0;
int main()
{
/* GCC complains about wrong number of template arguments (0, should be at least 1)
while CLang complains about redefinition of 'variable' */
std::cout << variable<> << '\n';
return 0;
}
模板别名
template <typename T, typename U = int> using alias = int;
template <typename T = int, typename U> using alias = int;
int main()
{
/* GCC complains about redefinition of 'alias'
while CLang compiles just fine. */
alias<> v = 0;
std::cout << v << '\n';
return 0;
}
有关该功能的标准文本没有区分不同的模板类型,因此我认为它们应该表现出相同的行为。
但是,两个编译器都拒绝了模板变量的情况,因此我对模板变量选项有些怀疑。对我来说,CLang拒绝模板变量并抱怨重定义是正确的,而GCC因为错误的原因而拒绝了代码,但这种推理并不符合标准中[ temp.param] / 10所说的内容。
那么对于模板变量的情况,我应该期望什么呢?:
- 由于重定义而被拒绝的代码(CLang是正确的)。
- 接受代码,合并两个模板定义(GCC和CLang都是错误的)。