在下面的代码中,编译器可以成功地将对f()
的调用解析为对f(int&, const char*)
的调用。
对g()
的调用是不明确的。它列出了所有四种重载作为可能的重载集。如果我从数组参数的模板参数列表中删除, typename T2, std::size_t I
,并对它们进行硬编码,则没有歧义,编译器会选择g(T&, const char*)
。
为什么添加两个模板参数会使这变得模棱两可?我可以看到,通过衰减和强制转换,它可以解决任何一个重载,但我不能弄清楚添加这些模板形参是如何引入歧义的。
我已经在Clang 3.8(未发布)和vc++ 2015上进行了测试。
#include <string>
void f(int&, const char*){}
void f(int&, char(&)[8]){}
void f(int&, bool){}
void f(int&, const std::string&){}
template <typename T>
void g(T&, bool){}
template <typename T>
void g(T&, const char*){}
template <typename T>
void g(T&, const std::string&){}
template <typename T, typename T2, std::size_t I>
void g(T&, T2(&)[I]){}
int main(int argc, char* argv[])
{
int i = 1;
f(i, " ");
g(i, " ");
return 0;
}
超载#2:
void g(T&, const char*){}
过载# 4:
template <typename T, typename T2, std::size_t I>
void g(T&, T2(&)[I]){}
当使用字符串字面量调用g(...)
时,过载#2和过载#4将是二义性的;字符串字面值参数将被推导为const char*
和T2(&)[I]
。
你的字符串字面值" "
是const char[8]
,这清楚地显示了它是如何被推断为过载#4的。然而,由于数组衰变成指针,const char[8]
也是const char*
,这显然可以推断出重载#2。
编译器通常会列出所有可能的重载,而不仅仅是有歧义的重载。所以重载1和3没有歧义。它们是二阶的。然而,重载2和重载4是一阶的——字符串文字是一个数组,数组衰减也是一阶的。