在 C++ 中选择可行的构造函数时,何时不考虑用户定义的转换序列?

When are user-defined conversion sequences not considered for selecting viable constructors in C++?

我在C++标准草案N4582中看到如下文字:

[over.best.ics/4] However, if the target is

(4.1) the first parameter of a constructor or

(4.2) the implicit object parameter of a user-defined conversion function

and the constructor or user-defined conversion function is a candidate by

(4.3) 13.3.1.3, when the argument is the temporary in the second step of a class copy-initialization, or

(4.4) 13.3.1.4, 13.3.1.5, or 13.3.1.6 (in all cases),

user-defined conversion sequences are not considered.

我对加粗部分一头雾水,不知道怎么理解。我写了下面的程序:

#include <iostream>
using namespace std;    
struct A {
    A(int) {}
    operator int() {cout << "user-defined conversion" << endl; return 0;}
    A(A&) {} //prevent default copy
};
int main()
{
    A a = A(0);
}

在g++5.3.0下运行良好,输出“user-defined conversion”,表示发生了用户自定义转换。当然,可以解释为临时A(0)不是copy-initialization的结果。接下来我将程序更改为:

#include <iostream>
using namespace std;    
struct A {
    A(int) {}
    operator int() {cout << "user-defined conversion" << endl; return 0;}
    A(A&) {} //prevent default copy
};
A foo() {return A(0);}
int main()
{
    A a = foo();
}

现在 foo() 的值是从 A(0) 初始化的临时副本,但程序仍然有效。为什么会这样?

您可以阅读 [dcl.init]/17 以了解实际的标准语。这里的 "second step" 是指从不相关类型的 b 中复制初始化 class 类型 A 的变量。在这种情况下,复制初始化分两步进行:

  • 第 1 步:将 b 隐式转换为 A。如果为此调用转换构造函数,它会创建一个临时的 A.
  • 第 2 步:然后根据转换结果初始化 A 变量。 (在理智的 classes 中,这通常被省略。)

这句话的意思是您不会在第二步中进行用户定义的转换。

例如,您的 AA a = 0;。在第一步中,您从 0 创建一个 A 临时文件。在第二步中,您尝试使用该临时值初始化 a - 不使用用户定义的转换。那失败了,因为 A 构造函数都不可行。

只有 2 个 ctors,一个引用现有对象(非临时对象),一个引用 int。

您的代码生成(带有附加消息):

int ctor
user-defined conversion
int ctor
user-defined conversion
int ctor

首先是foo里面的构造。

第二个是由于返回值不能像你阻止的那样通过复制构造,所以编译器将构造的值转换为int

第三个是因为它使用带有 int 的构造函数来构建返回值。

第四个(同第二个)由于返回值不能用来构造a,所以将其转换为int.

第五个是因为它随后使用采用 int 的构造函数来构建 a