C++ 调用重载<;括号内的初始值设定项列表>;是暧昧的,怎么处理呢?

C++ 调用重载<;括号内的初始值设定项列表>;是暧昧的,怎么处理呢?,c++,c++11,initializer-list,ambiguous,C++,C++11,Initializer List,Ambiguous,我真的不明白这一点,我认为编译器首先执行大括号中的内容,然后将结果提供给最合适的函数。这里看起来它给了函数一个初始化列表来处理它 #include <string> #include <vector> using namespace std; void func(vector<string> v) { } void func(vector<wstring> v) { } int main() { func({"apple", "banan

我真的不明白这一点,我认为编译器首先执行大括号中的内容,然后将结果提供给最合适的函数。这里看起来它给了函数一个初始化列表来处理它

#include <string>
#include <vector>
using namespace std;

void func(vector<string> v) { }

void func(vector<wstring> v) { }

int main() {
  func({"apple", "banana"});
}
#包括
#包括
使用名称空间std;
void func(向量v){}
void func(向量v){}
int main(){
func({“苹果”、“香蕉”});
}
错误:

<stdin>: In function 'int main()':
<stdin>:11:27: error: call of overloaded 'func(<brace-enclosed initializer list>)' is ambiguous
<stdin>:11:27: note: candidates are:
<stdin>:6:6: note: void func(std::vector<std::basic_string<char> >)
<stdin>:8:6: note: void func(std::vector<std::basic_string<wchar_t> >)
:在函数“int main()”中:
:11:27:错误:重载“func()”的调用不明确
:11:27:注:候选人包括:
:6:6:注:void func(标准::向量)
:8:6:注:void func(标准::向量)
为什么不调用我的
func(vector v)
重载,我可以这样做吗?

这一点很微妙

std::vector
有一个采用两个范围迭代器的构造函数。它是一个模板构造函数(在C++11标准的23.6.6.2中定义):

模板
向量(先输入计数器,后输入计数器,
常量分配器类型&a=分配器类型();
现在,
std::vector
接受
初始值设定项列表的构造函数与函数调用中的隐式转换不匹配,(
const char*
string
是不同的类型);但是上面的一个,当然包括在
std::vector
std::vector
中,是一个潜在的完美匹配,因为
inputierator
可以推断为
const char*
。除非使用某种SFINAE技术来检查推导出的模板参数是否确实满足向量基础类型的
inputierator
概念(这不是我们的情况),否则此构造函数是可行的

但是,同样地,
std::vector
std::vector
都有一个可行的构造函数,它实现了从带括号的初始值设定项列表的转换:因此,存在歧义

所以问题在于,尽管
“apple”
“banana”
不是真正的迭代器(*),但它们最终被视为迭代器。在函数调用中添加一个参数“joe”
,通过消除调用的歧义来解决问题,因为这会迫使编译器排除基于范围的构造函数,并选择仅可行的转换(
initializer\u list
不可行,因为无法将
const char*
转换为
wstring



*实际上,它们是指向
常量字符的指针,因此它们甚至可以被视为字符的常量迭代器,但绝对不是我们的模板构造函数所认为的字符串的常量迭代器。

@OmnipotentEntity:谢谢:-)现在我更讨厌所谓的“统一初始化”,它干扰了我喜欢的特性,
std::initializer\u list
@Praetorian:你说得对,但作为
char
s的常量迭代器,而不是
string
s或
wstring
s的常量迭代器,你的描述让我觉得“这个构造函数比initializer list构造函数更匹配,所以它是首选的”。但是,如果将两个构造函数相互比较,那么即使模板构造函数会更好地匹配,编译器仍然会使用初始值设定项列表构造函数。因为编译器首先只查看初始值设定项列表构造函数。只有当它们根本不匹配时,它才会另外考虑所有其他构造函数,这次将初始值设定项列表元素单独作为参数,而不是整个列表。@AndyProwl因为对于
vector
,它选择模板构造函数,然后两者都匹配,没有一个比另一个更好。如果其中一个
func
s的参数类型为
std::initializer_list
,而另一个则不是,则首选
func
。与嵌套重载解析上下文相比,这并不重要,函数的一个参数使用初始值设定项列表构造函数来初始化自身。重要的是参数类型本身,在这两种情况下都是
vector
template<typename InputIterator>
vector(InputIterator first, InputIterator last, 
const allocator_type& a = allocator_type());