重载解决方案:是否首选直接转换运算符(作为复制省略的结果)?

Overload-Resolution: Is a direct conversion operator preferred (as a consequence of copy-elision)?

给出

struct E
{
};

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

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

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

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

我认为正确的行为符合标准是不明确的。

[dcl.init]/17.1:

If the initializer is a (non-parenthesized) braced-init-list or is = braced-init-list, the object or reference is list-initialized.

[dcl.init.list]/3.6:

Otherwise, if T is a class type, constructors are considered. The applicable constructors are enumerated and the best one is chosen through overload resolution ([over.match], [over.match.list]). If a narrowing conversion (see below) is required to convert any of the arguments, the program is ill-formed.

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


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

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

Dog d;
Cat c(d);

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