用户定义的转换序列

Use*_*049 19 c++ type-conversion implicit-conversion

在我研究explicit关键字之前,我的老师说:"编译器不执行连续的用户定义转换".如果是,我的代码中是否有任何错误?或者我误解了我的老师?我在VS2017工作.

#include<iostream>
#include <string>

class Myclass {
public:
    Myclass() {
        std::cout << "Myclass" << std::endl;
    }
};

class Myclass1 {
public:
    Myclass1(Myclass m) {
        std::cout << "Myclass1" << std::endl;
    }
};
class Myclass2{
public:
    Myclass2(Myclass1 m) {
        std::cout << "Myclass2" << std::endl;
    }
};

int main() {
    Myclass2 m2 = Myclass{};
} 
Run Code Online (Sandbox Code Playgroud)

Afs*_*hin 13

编译器不执行连续的用户定义转换

你的老师是对的.在您的代码示例中,它表示在您分配时Myclass无法转换为Myclass1:

Myclass2 m2 = Myclass{};
Run Code Online (Sandbox Code Playgroud)

因为构造函数Myclass1在创建时期望Myclass2,并且编译器不能连续转换MyclassMyclass1然后用它来创建Myclass2.但如果您有以下行:

Myclass1 m2 = Myclass{};
Run Code Online (Sandbox Code Playgroud)

它将工作,因为构造函数Myclass1需要Myclass作为参数.

更新:

您可能会问为什么这样做:

Myclass2 m2 {Myclass{}};
Run Code Online (Sandbox Code Playgroud)

因为在这种情况下,调用构造函数和转换可以隐除非你声明来完成Myclass1explicit,这将失败,代码编译(感谢Fureeish为提醒),但在:

Myclass2 m2 = Myclass{};
Run Code Online (Sandbox Code Playgroud)

就像调用需要引用的copy-constructor一样.所以如果你这样写,它会工作:

Myclass2 m2 = Myclass1(Myclass{});
Run Code Online (Sandbox Code Playgroud)

EVG所述,Myclass2 m2 = Myclass{};如果未激活一致性模式(/ permissive-),VS 2017将接受.

  • 值得注意的是,OP提到了"明确的".在你编辑的第一个例子中,有一个临时的`Myclass1`对象*来自`myclass`实例*隐含**这就是为什么调用了一个`Myclass2`构造函数,这需要`Myclass1`对象).如果你使`Myclass1`的构造函数`explicit`,它将会失败 (2认同)

Evg*_*Evg 8

这条线

 Myclass2 m2 = Myclass{};
Run Code Online (Sandbox Code Playgroud)

表示复制初始化.引用cppreference.com:

如果T是一个类类型,和类型的CV-不合格版本other没有T或衍生自T可从的类型转换[...],用户定义的转换序列other,以T[...]被检查和最佳的通过重载决策选择一个.

进一步引用:

用户定义的转换由零个或一个非显式单参数构造函数或非显式转换函数调用组成.

因此,这Myclass2 m2 = Myclass{};是不可接受的,因为它涉及两个用户定义的转换.


现在让我们来看看

Myclass2 m2 {Myclass{}};
Run Code Online (Sandbox Code Playgroud)

Afshin的回答中提出.这是一个直接初始化.规则不同:

T检查构造函数,并通过重载决策选择最佳匹配.然后调用构造函数来初始化对象.

的构造函数Myclass2接受Myclass1,你需要一个用户自定义转换得到Myclass1Myclass.因此,它编译.


请注意,在VS 复制中,如果未激活一致性模式(),则将其视为直接/premissive-启动(默认情况下).因此,VS接受Myclass2 m2 = Myclass{};将其视为直接启动.有关示例,请参阅此文档.