我的问题涉及这个非常简单和简短的代码,其中在接受数组引用参数的两个非模板函数之间尝试重载解析。该问题已在其他地方发布,但在模板演绎上下文中。这是代码:
#include <iostream>
void foo ( const int (&x) [3] ) { std::cout << "3\n"; }
void foo ( const int (&x) [2] ) { std::cout << "2\n"; }
int main()
{
foo({1,2,3});
}
g ++ 4.8.3编译此代码选择第一个函数为(我想)唯一可行的, 虽然clang 3.4没有编译它,但是对foo的调用是模棱两可的(为什么?)。
哪种编译器做对了?
clang甚至没有编译代码,甚至删除第二个重载:似乎不接受初始化数组引用的初始化列表。
这辆车有问题吗?
答案 0 :(得分:6)
我认为虽然GCC的行为更有用,但它的行为对C ++ 11来说是正确的:
13.3.3.1.5列表初始化序列[over.ics.list]
2如果参数类型为
std::initializer_list<X>
或&#34;数组为X
&#34;并且初始化列表的所有元素都可以隐式转换为X
,隐式转换序列是将列表元素转换为X
所需的最差转换。
此转换序列不关注数组长度。两个函数重载都提供了一个隐式转换序列,即身份转换:两者都引用int
数组,函数参数中的每个元素都是int
。
重载决策然后会看到两个身份转换,虽然标准确实有一些例外可以解决同等级别转换的冲突,但没有一个能够关注数组的长度:
13.3.3.2对隐式转换序列进行排名[over.ics.rank]
3两个相同形式的隐式转换序列是无法区分的转换序列,除非符合以下规则之一:
后跟一个完全没有提及数组的列表。
Jonathan Wakely指出,此后发生了变化。您的问题正是促使该更改的原因,相应的DR为#1307。在C ++ 14中,您的代码是有效的,但在C ++ 11中则无效。
答案 1 :(得分:4)