请考虑以下代码:
#include <iostream>
#include <vector>
void f(std::vector<int> v) {std::cout << __PRETTY_FUNCTION__ << std::endl;}
void f(int n) {std::cout << __PRETTY_FUNCTION__ << std::endl;}
int main()
{
f({42}); // the int overload is being picked up
}
我有点意外地意识到在这种情况下正在拾取int重载,即程序的输出是:
void f(int)
带警告
警告:标量初始化器周围的大括号[-Wbraced-scalar-init] f({42});
当然,只有当我将1元素列表作为参数传递时才会发生这种情况,否则会发现std::vector
重载。
为什么{42}
被视为标量而不是初始列表?有没有办法迫使编译器选择std::vector
重载(没有明确构建std::vector<int>{42}
),即使在单元素列表上也是如此?
PS:std::vector
有一个init-list构造函数
vector(std::initializer_list<T> init, const Allocator& alloc = Allocator());
见cppreference中的(7)。
答案 0 :(得分:6)
支持初始化程序没有类型,我们不能说{42}
是int
或std::initializer_list<int>
。当它用作参数时,special rules for overload resolution将应用于重载函数调用。
(强调我的)
- 否则,如果参数类型不是类且初始化列表有一个元素,则隐式转换序列是将元素转换为参数类型
{42}
只有一个类型为int
的元素,然后它与重载void f(int)
完全匹配。而对于void f(std::vector<int>)
,则需要用户定义的转换。因此,void f(int)
将在这里被选中。
是否有任何方法可以强制编译器选择
std::vector
重载(即使在单元素列表中也没有明确构造std::vector<int>{42})
?
作为一个单词,您可以添加其他大括号以强制编译器构造std::initializer_list<int>
,然后选择void f(std::vector<int>)
:
f({{42}});
答案 1 :(得分:1)
强制std :: vector重载
int main()
{
f(std::vector<int>{42}); // the vector overload is being picked up now
}
为什么vector(initializer_list)
构造函数没有被选中?
假设另一个标头声明void f(std::set<int> v)
。
您希望编译器在面对f({1})
时做出反应:构建vector
还是构建set
?