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

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

考虑以下代码:

#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 重载,即程序的输出是:

void f(int)

有警告

warning: braces around scalar initializer [-Wbraced-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());

参见 cppreference 中的 (7)。

强制std::vector过载

int main()
{
    f(std::vector<int>{42}); // the vector overload is being picked up now
}

为什么 vector(initializer_list) 构造函数没有被拾取?

假设另一个 header 声明了一个 void f(std::set<int> v)

您希望编译器在遇到 f({1}) 时如何反应:构造一个 vector 还是构造一个 set

大括号初始化器没有类型,我们不能说 {42}intstd::initializer_list<int>。当它用作参数时,special rules for overload resolution 将应用于重载函数调用。

(强调我的)

  • Otherwise, if the parameter type is not a class and the initializer list has one element, the implicit conversion sequence is the one required to convert the element to the parameter type

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

Is there any way of forcing the compiler to pick the std::vector overload (without explicitly constructing std::vector<int>{42}) even on 1-element lists?

作为一种变通方法,您可以添加额外的大括号以强制编译器构造一个 std::initializer_list<int> 然后选择 void f(std::vector<int>):

f({{42}});

LIVE