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


20

考虑以下代码:

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

https://godbolt.org/z/Gc_w8i

打印:

vector overload
int overload

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

可以肯定地进一步减少构造函数的签名,但是我只是被等效的代码所欺骗,并希望确保对该问题没有任何重要的认识。


如果我{}作为一个代码块正确地回想起,则将0赋给变量-例如:const char x = {}; 被设置为0(空字符),同样对于int等
塞提

2
@Seti这就是{}在某些特殊情况下,有效的做法,但它不是通常是正确的(对于初学者来说,std::vector<int> x = {};工作的,std::vector <int> x = 0;不)。它不像“ {}分配零” 那样简单。
马克斯·朗霍夫

是的,它不是那么简单,但是它仍然分配零-以为我认为这种行为非常令人困惑,不应该真正使用
Seti

2
@Seti struct A { int x = 5; }; A a = {};没有在任何意义上分配了零,构建一个Aa.x = 5。这与A a = { 0 };不会初始化a.x为0的情况不同。零不是固有的{},它对于每种类型如何进行默认构造或值初始化是固有的。看到这里这里这里
Max Langhof

我仍然认为默认构造的值令人困惑(要求您始终检查行为或保持足够的知识)
Seti

Answers:


12

[over.ics.list]中,重点是我的

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

  • 如果C 不是初始值设定项列表构造函数,并且初始值设定项列表具有 cv U类型的单个元素,其中U是X或从X派生的类,则隐式转换序列在U是X时具有完全匹配等级,在U则是转换等级U是从X派生的。

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

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

  • [...]

  • 如果初始化列表中没有元素,则隐式转换序列为身份转换。[示例:

    void f(int);
    f( { } ); // OK: identity conversion

    结束示例

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


是的,看起来很准确。
哥伦布

有趣的是,在标准中明确考虑了这种情况。我真的希望它是模棱两可的(看起来可以很容易地用这种方式指定它)。我无法遵循您在最后一句话中的推理- 0具有类型int但没有类型std::vector<int>,这如何“仿佛”到的“无类型”性质{}
Max Langhof

@MaxLanghof-另一种查看方式是,对于非类类型,它不是用户定义的转换。相反,它是默认值的直接初始化程序。因此,在这种情况下是一个身份。
StoryTeller-Unslander Monica

那部分很清楚。我对用户定义的转换需求感到惊讶std::vector<int>。正如您所说,我期望“参数的类型最终决定参数的类型”,并且{}“类型”(可以这么说)std::vector<int>应该不需要(非身份)转换来初始化a std::vector<int>。该标准显然表明确实如此,仅此而已,但对我而言却没有意义。(请记住,我不是在争论您或标准是错误的,只是试图将其与我的思维模式进行调和。)
Max Langhof

好的,该编辑不是我希望的分辨率,但足够公平。:D谢谢您的时间!
马克斯·朗霍夫
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.