显式强制转换,直接初始化和复制初始化之间的行为不同 [英] Different behavior among explicit cast, direct initialization and copy initialization
问题描述
我有一个类C
,它具有任何类型的转换运算符.在示例中,我尝试以三种不同的方式将其实例转换为std::string
:static_cast
,std::string
的构造函数并分配给std::string
.但是,只有最后一个会编译,而其他会引发构造函数模棱两可的错误.
I have a class C
which has a casting operator to anything. In the example I tried to cast an instance of it to std::string
in three different ways: static_cast
, constructor of std::string
and assigning to std::string
. However, only the last one compiles, while the others raise an error of ambiguous constructor.
错误的原因很明显:有很多方法可以将C
转换为std::string
的构造函数可以接受的东西.但是,这两种情况有什么区别?为什么强制转换运算符在这里但不在那里按预期工作?
The reason of the error is clear enough: there are many ways to convert C
to something which the constructor of std::string
can accept. But what is the difference between these cases? Why cast operator works as intended here but not there?
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对其进行了测试,它显示了所描述的错误.
UPD: as bolov mentioned in comments, this issue doesn't reproduce with C++17. I tested it with g++-5 and clang-3.8 with -std=c++11 and -std=c++14, and it shows the described errors.
推荐答案
在C ++ 17之前
static_cast<string>(c)
和string bad(c)
执行直接初始化,然后
检查
T
的构造函数,并通过重载分辨率选择最佳匹配.然后调用构造函数以初始化对象.
the constructors of
T
are examined and the best match is selected by overload resolution. The constructor is then called to initialize the object.
正如您所说,std::string
的所有可能的构造函数都会被检查,并且C
可以转换为所需的任何内容,然后造成歧义.
As you said, all the possible constructors of std::string
are examined and C
can be converted to anything required, then causes ambiguity.
string ok = c
执行复制初始化(请注意,这不是分配),然后
string ok = c
performs copy initialization (note it's not assignment), then
如果
T
是类类型,并且other
类型的cv不合格版本不是T
或从T
派生,或者T
是非类类型,但是other
的类型是类类型,用户定义的转换序列可以从other
的类型转换为T
(如果T
是类类型和转换,则可以转换为从T
派生的类型)功能可用)进行检查,并通过过载分辨率选择最佳的.
If
T
is a class type, and the cv-unqualified version of the type ofother
is notT
or derived fromT
, or ifT
is non-class type, but the type ofother
is a class type, user-defined conversion sequences that can convert from the type ofother
toT
(or to a type derived fromT
ifT
is a class type and a conversion function is available) are examined and the best one is selected through overload resolution.
这意味着将检查从C
到std::string
的转换,并将其用于此处的初始化.
That means the conversion from C
to std::string
is examined, and used for the initialization here.
在C ++ 17之后
从C ++ 17开始,用于直接初始化,
Since C++17 for direct initlizatioin,
如果初始化程序是一个prvalue表达式,其cv不合格类型与
T
是同一类,则初始化程序表达式本身(而不是从其实例化的)用于初始化目标对象:请参见复制省略(自C ++ 17起)
if the initializer is a prvalue expression whose cv-unqualified type is the same class as
T
, the initializer expression itself, rather that a temporary materialized from it, is used to initialize the destination object: see copy elision (since C++17)
这意味着将执行从C
到std::string
的转换并将其用于初始化,然后模糊性消失并且代码运行良好.
That means the conversion from C
to std::string
is perferred and used for the initialization, then the ambiguity disappears and the code works well.
这篇关于显式强制转换,直接初始化和复制初始化之间的行为不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!