简体   繁体   English

用户定义的转换序列

[英]User-defined conversions sequence

Before I studied the explicit keyword, my teacher said: "compiler doesn't execute consecutive user defined conversion". 在我研究explicit关键字之前,我的老师说:“编译器不执行连续的用户定义转换”。 If it is true, are there any errors in my code? 如果是,我的代码中是否有任何错误? Or have I misunderstood my teacher? 或者我误解了我的老师? I'm working in VS2017. 我在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{};
} 

compiler doesn't execute consecutive user defined conversion 编译器不执行连续的用户定义转换

Your teacher is right. 你的老师是对的。 In your code sample it means Myclass cannot be converted to Myclass1 when you assign in: 在您的代码示例中,这意味着当您分配时, Myclass无法转换为Myclass1

Myclass2 m2 = Myclass{};

Because constructor expects Myclass1 when creating Myclass2 , and compiler cannot consecutively convert Myclass to Myclass1 and then use it for creating Myclass2 . 因为构造Myclass1在创建Myclass1时需要Myclass2 ,并且编译器不能将Myclass连续转换为Myclass1 ,然后使用它来创建Myclass2 But if you have following line: 但如果您有以下行:

Myclass1 m2 = Myclass{};

It will work, because constructor of Myclass1 takes Myclass as argument. 它会工作,因为Myclass1构造Myclass1Myclass作为参数。

Update: 更新:

You may ask why this works: 您可能会问为什么这样做:

Myclass2 m2 {Myclass{}};

Because in this case, constructor is called and conversion can be done implicitly unless you declare Myclass1 as explicit which will fail code compilation (Thanks Fureeish for reminder), but in: 因为在这种情况下,构造函数被调用并且可以隐式地进行转换,除非您将Myclass1声明为explicit ,这将使代码编译失败(感谢Fureeish提醒),但是:

Myclass2 m2 = Myclass{};

is like calling copy-constructor which needs reference. 就像调用需要引用的copy-constructor一样。 so if you write it like this, it will work: 所以如果你这样写,它会工作:

Myclass2 m2 = Myclass1(Myclass{});

As EVG mentioned, Myclass2 m2 = Myclass{}; 正如EVG所提到的, Myclass2 m2 = Myclass{}; is accepted by VS 2017 if the conformance mode (/permissive-) is not activated. 如果未激活一致性模式(/ permissive-),则VS 2017接受。

The line 这条线

 Myclass2 m2 = Myclass{};

means copy-initialization . 表示复制初始化 Citing cppreference.com : 引用cppreference.com

If T is a class type, and the cv-unqualified version of the type of other is not T or derived from T [...], user-defined conversion sequences that can convert from the type of other to T [...] are examined and the best one is selected through overload resolution. 如果T是类类型,并且other类型的cv-nonqualified版本不是T或从T [...]派生,则用户定义的转换序列可以从other类型转换为T [...检查并通过重载分辨率选择最佳的一个。

Citing further : 进一步引用:

A user-defined conversion consists of zero or one non-explicit single-argument constructor or non-explicit conversion function call. 用户定义的转换由零个或一个非显式单参数构造函数或非显式转换函数调用组成。

So, Myclass2 m2 = Myclass{}; 所以, Myclass2 m2 = Myclass{}; is not acceptable because it would involve two user-defined conversions. 是不可接受的,因为它涉及两个用户定义的转换。


Now let's take a look at 现在让我们来看看

Myclass2 m2 {Myclass{}};

suggested in Afshin 's answer. Afshin的回答中提出。 This is a direct-initialization . 这是一个直接初始化 The rules are different : 规则不同

The constructors of T are examined and the best match is selected by overload resolution. 检查T的构造函数,并通过重载决策选择最佳匹配。 The constructor is then called to initialize the object. 然后调用构造函数来初始化对象。

The constructor of Myclass2 accepts Myclass1 , and you need one user-defined conversion to get Myclass1 from Myclass . Myclass2的构造Myclass2接受Myclass1 ,您需要一个用户定义的转换才能从Myclass获取Myclass1 Hence, it compiles. 因此,它编译。


Note that in VS copy-initilization is treated like direct-initilization if conformance mode ( /premissive- ) is not activated (by default). 请注意,在VS 复制中,如果未激活一致性模式( /premissive- )(默认情况下),则会将其视为直接启动。 So, VS accepts Myclass2 m2 = Myclass{}; 所以,VS接受Myclass2 m2 = Myclass{}; treating it as direct-initilization . 将其视为直接启动 See this document for examples. 有关示例,请参阅此文档

The other answers are burying the lede: The code you've written is indeed invalid . 其他答案正在埋葬lede:你写的代码确实无效 MSVC accepts it by default, but MSVC is wrong to do so. MSVC默认接受它,但MSVC这样做是错误的。 You can force MSVC to be stricter by using the command line switch /permissive- . 您可以使用命令行开关/permissive-强制MSVC更严格。 ( You should use that switch .) 你应该使用那个开关 。)

Other compilers (GCC, clang), reject it. 其他编译器(GCC,clang)拒绝它。

All compilers accept the code once you change the copy initialisation to direct initialisation as shown in the other answers. 一旦您将副本初始化更改为直接初始化,所有编译器都会接受代码,如其他答案所示。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM