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测试它,它显示了所描述的错误.
在C++之前17
static_cast<string>(c)并string bad(c)进行直接初始化,然后
T检查构造函数,并通过重载决策选择最佳匹配.然后调用构造函数来初始化对象.
如你所说,所有可能的构造函数std::string都经过检验,C可以转换为任何需要的构造函数,然后导致歧义.
string ok = c然后执行复制初始化(注意它不是赋值)
如果
T是类类型,并且类型的cv-nonqualified版本other不是T或派生自T,或者如果T是非类类型,但类型other是类类型,则可以从类型转换的用户定义转换序列的other到T(或从衍生的类型T,如果T是一个类类型和一个转换功能是可用的)进行检查和最好的一个是通过重载解析选择.
这意味着检查从转换C到std::string,并在此处用于初始化.
在C++之后17
由于C++ 17用于直接初始化,
如果初始化程序是一个prvalue表达式,其cv-unqualified类型与它是同一个类
T,则初始化程序表达式本身,而不是从中实现的临时表达式,用于初始化目标对象:请参阅copy elision(自C++ 17起)
这意味着转换为Cto std::string并被用于初始化,然后模糊消失并且代码运行良好.