我编写了一个有两个重载的函数 – 一个用于单个指针,一个用于指针向量。在代码中的某个时刻,我想将一个空向量传递给函数并用作{}参数。

#include <vector>
#include <iostream>

void f(std::vector<const int*> v)
{
    std::cout << "vector overload" << std::endl;
}
 
void f(const int* i)
{
    std::cout << "pointer overload" << std::endl;
}

int main()
{
    f({});
    return 0;
}

不幸的是,这不会调用具有空向量的向量重载,而是调用具有的指针重载nullptr

该问题的解决方案是用引用替换指针重载,因为无法用 进行初始化{}

void f(const int& i);

为什么编译器不会抱怨模糊调用?为什么它更喜欢指针重载?


最佳答案
3

因为从大括号列表到 的转换std::vector被归类为用户定义的转换序列,其等级较低。

您可以添加另一个std::initializer_list优先的过载。例如

void f(std::initializer_list<const int*> v)
{
    f(std::vector<const int*>(v)); // forward to the overload taking std::vector
}

编译器倾向于选择需要较少转换(最好不需要)的重载。

在这种情况下,可以直接从 初始化指针{}

例如,您可以使用:

const int* p{};  // will initialize `p` to `nullptr`

因此,最好调用第二个重载,而不是创建一个std::vector<const int*>from {}(用户定义的转换)来调用第一个重载。

2

  • 1
    您也可以这样做std::vector<const int*> v{};,所以我仍然不确定这两者之间有什么区别。


    – 

  • 3
    {}从到 的转换std::vector是用户定义转换,而对于指针则不是。


    – 

让我们首先考虑一下当指定函数重载时会发生什么。编译器将在编译期间搜索歧义调用,因此我们可以立即消除运行时错误,并严格遵守此时的语义。编译器仅在执行重载函数中的参数匹配时才会抱怨歧义调用。在函数重载期间,编译器将生成候选函数以形成候选集。候选集是按照函数加载语义生成的,其中按顺序检查函数参数,并且推断/隐含的函数参数也遵循类似的分析。此时,如果函数参数类型根据参数选择语义转换为另一种类型或衰减(参数类型的值衰减的转换)为另一种类型。候选集中所述重载函数的重叠不会导致编译器抛出歧义调用警告。函数重载选择将遵循执行开销最小的重载。本质上,指针重载是首选,因为它在优先级排名列表中排名较高,(指针类型不是用户定义类型)。我尝试详细了解编译器在排列优先级时所采用的语义。希望这能有所帮助。