我有一个类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
}
UPD :正如bolov在评论中提到的,这个问题并没有用C ++ 17重现。我用g ++ - 5和clang-3.8用-std = c ++ 11和-std = c ++ 14测试它,它显示了所描述的错误。
答案 0 :(得分:6)
在C ++ 17之前
static_cast<string>(c)
和string bad(c)
执行direct initialization,然后
检查
T
的构造函数,并通过重载决策选择最佳匹配。然后调用构造函数来初始化对象。
正如你所说,std::string
的所有可能的构造函数都会被检查,C
可以转换为任何需要的构造函数,然后引起歧义。
string ok = c
执行copy initialization(请注意,这不是作业),然后
如果
T
是类类型,并且other
类型的cv-nonqualified版本不是T
或来自T
,或{{1} }}是非类型,但T
的类型是类类型,用户定义的转换序列,可以从other
的类型转换为other
(或类型)如果T
是类类型并且转换函数可用,则从T
派生,并且通过重载决策选择最佳的一个。
这意味着会检查从T
到C
的转换,并在此处用于初始化。
在C ++ 17之后
自direct initlizatioin的C ++ 17以来,
如果初始化程序是一个prvalue表达式,其cv-unqualified类型与
std::string
是同一个类,则初始化程序表达式本身,而不是从中实现的临时表达式,用于初始化目标对象:请参阅{{ 3}}(自C ++ 17起)
这意味着从T
转换为C
并将其用于初始化,然后模糊性消失,代码运行良好。