为什么 {} 作为函数参数不会导致歧义?

Max*_*hof 20 c++ language-lawyer overload-resolution

考虑这个代码:

#include <vector>
#include <iostream>

enum class A
{
  X, Y
};

struct Test
{
  Test(const std::vector<double>&, const std::vector<int>& = {}, A = A::X)
  { std::cout << "vector overload" << std::endl; }

  Test(const std::vector<double>&, int, A = A::X)
  { std::cout << "int overload" << std::endl; }
};

int main()
{
  std::vector<double> v;
  Test t1(v);
  Test t2(v, {}, A::X);
}
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/Gc_w8i

这打印:

vector overload
int overload
Run Code Online (Sandbox Code Playgroud)

为什么由于重载解析不明确而不会产生编译错误?如果删除第二个构造函数,我们会得到vector overload两次。如何/由什么指标是int一个明确更好地匹配了{}std::vector<int>

构造函数签名当然可以进一步修剪,但我只是被一段等效的代码所欺骗,并想确保这个问题没有丢失任何重要的东西。

Sto*_*ica 12

它在[over.ics.list] 中,强调我的

6否则,如果参数是非聚合类 X 并且每个 [over.match.list] 的重载决议选择 X 的单个最佳构造函数 C 来执行参数初始化器列表中类型 X 对象的初始化:

  • 如果 C不是初始化列表构造函数并且初始化列表有一个cv U 类型的元素,其中 U 是 X 或从 X 派生的类,则隐式转换序列在 U 是 X 时具有精确匹配等级,如果 U 为 X 则具有转换等级U 源自 X。

  • 否则,隐式转换序列是用户定义的转换序列,第二个标准转换序列是恒等转换。

9否则,如果参数类型不是类:

  • [...]

  • 如果初始值设定项列表没有元素,则隐式转换序列是身份转换。[?例子:

    void f(int);
    f( { } ); // OK: identity conversion
    
    Run Code Online (Sandbox Code Playgroud)

    结束例子?]

std::vector被构造和大胆的认为有一个用户定义的converison子弹初始化。同时,对于 an int,这是身份转换,因此它胜过第一个 c'tor 的等级。