显式转换,直接初始化和复制初始化之间的不同行为

Iva*_*nov 7 c++ templates casting initialization language-lawyer

我有一个C有任何铸造操作员的课程.在示例中,我尝试以std::string三种不同的方式转换它的实例:static_cast,构造函数std::string和赋值std::string.但是,只有最后一个编译,而其他人引发了模糊构造函数的错误.

错误的原因很明显:有很多方法可以转换C为构造函数std::string可以接受的东西.但这些案件有什么区别?为什么演员在这里按预期工作但不在那里?

struct C {
    template<typename T>
    operator T() const {
        return T{};
    }
};

int main() {
    C c;

    cout << static_cast<string>(c) << endl; // compile error
    string bad(c); // compile error
    string ok = c; // compiles successfully
}
Run Code Online (Sandbox Code Playgroud)

UPD:正如bolov在评论中提到的,这个问题不能用C++ 17重现.我用g ++ - 5和clang-3.8用-std = c ++ 11和-std = c ++ 14测试它,它显示了所描述的错误.

son*_*yao 6

在C++之前17

static_cast<string>(c)string bad(c)进行直接初始化,然后

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

如你所说,所有可能的构造函数std::string都经过检验,C可以转换为任何需要的构造函数,然后导致歧义.

string ok = c然后执行复制初始化(注意它不是赋值)

如果T是类类型,并且类型的cv-nonqualified版本other不是T或派生自T,或者如果T是非类类型,但类型other是类类型,则可以从类型转换的用户定义转换序列的otherT(或从衍生的类型T,如果T是一个类类型和一个转换功能是可用的)进行检查和最好的一个是通过重载解析选择.

这意味着检查从转换Cstd::string,并在此处用于初始化.

在C++之后17

由于C++ 17用于直接初始化,

如果初始化程序是一个prvalue表达式,其cv-unqualified类型与它是同一个类T,则初始化程序表达式本身,而不是从中实现的临时表达式,用于初始化目标对象:请参阅copy elision(自C++ 17起)

这意味着转换为Cto std::string并被用于初始化,然后模糊消失并且代码运行良好.

生活