重载分辨率:是否需要直接转换运算符(由于copy-elision)?

问题描述 投票:10回答:1

特定

struct E
{
};

struct P
{
    explicit P(E) {}
};

struct L
{
    operator E() {return {};}
    operator P() {return P{E{}};}
};

根据C ++ 17语言标准,表达式P{L{}}应该编译吗?

不同的编译器产生不同的结果:

  • gcc(trunk):好的
  • gcc 8.3:错误(过载模糊)
  • gcc 7.4:好的
  • clang(trunk):好的
  • clang 8.0.0:好的
  • clang 7.0.0:好的
  • msvc v19.20:错误(过载模糊)
  • icc 19.0.1:错误(多个构造函数实例匹配)
c++ language-lawyer c++17 overload-resolution copy-elision
1个回答
4
投票

我认为每个标准的正确行为是模棱两可的。

[dcl.init]/17.1

如果初始化程序是(非括号的)braced-init-list或is = braced-init-list,则对象或引用将进行列表初始化。

[dcl.init.list]/3.6

否则,如果T是类类型,则考虑构造函数。枚举适用的构造函数,并通过重载决策([over.match],[over.match.list])选择最佳构造函数。如果转换任何参数需要缩小转换(见下文),则程序格式错误。

[over.match.list]只是谈论选择一个构造函数。我们有两个可行的选择:P(E)通过L{}.operator E()P(P&&)(隐式移动构造函数)通过​​L{}.operator P()。没有比另一个更好。


然而,这非常让人想起CWG 2327

struct Cat {};
struct Dog { operator Cat(); };

Dog d;
Cat c(d);

问题表明当前调用Cat(Cat&&)而不仅仅是d.operator Cat(),并建议我们实际上也应该考虑转换函数。但它仍然是一个悬而未决的问题。我不确定gcc或clang在回答这个问题时做了什么(或者回应了先提出的类似例子),但根据你的结果,我怀疑他们认为直接转换函数L{}.operator P()是一个更好的匹配,就这样做

© www.soinside.com 2019 - 2024. All rights reserved.