在只有一个元素的列表上强制std::vector重载而不是int重载

Forcing std::vector overload instead of int overload on list with one element

本文关键字:重载 vector int std 元素 有一个 列表      更新时间:2023-10-16

考虑以下代码:

#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
}

Live on Coliru

我有点惊讶地意识到,在这种情况下,int重载被拾取,即程序的输出是:

空白f (int)

带有警告的

警告:大括号环绕标量初始化项[- brace -scalar-init] f({42});

当然,这只发生在我传递一个包含1个元素的列表作为参数时,否则std::vector过载将被拾取。

为什么{42}被视为标量而不是初始化列表?是否有任何方法强迫编译器选择std::vector过载(没有显式构造std::vector<int>{42}),甚至在1元素列表?

PS: std::vector有一个初始化列表构造函数

vector(std::initializer_list<T> init, const Allocator& alloc = Allocator());

参见(7)from cppreference

括号初始化器没有类型,我们不能说{42}intstd::initializer_list<int>。当它被用作实参时,重载函数调用将应用重载解析的特殊规则。

(强调我的)

    否则,如果形参类型不是类,且初始化列表只有一个元素,则隐式转换序列是将元素转换为形参类型所需的转换序列。

{42}只有一个类型为int的元素,那么它与重载void f(int)完全匹配。而对于void f(std::vector<int>),则需要用户定义的转换。因此,void f(int)将在这里拾取。

是否有任何方法可以强制编译器选择std::vector过载(即使在1元素列表上也不显式构造std::vector<int>{42})) ?

作为转义,您可以添加额外的大括号来强制编译器构造std::initializer_list<int>,然后拾取void f(std::vector<int>):

f({{42}});
生活

强制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 ?