Different behavior among explicit cast, direct initialization and copy initialization

大兔子大兔子 提交于 2019-12-21 12:15:03

问题


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.

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: 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.


回答1:


Before C++17

static_cast<string>(c) and string bad(c) performs direct initialization, then

the constructors of T are examined and the best match is selected by overload resolution. The constructor is then called to initialize the object.

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 performs copy initialization (note it's not assignment), then

If T is a class type, and the cv-unqualified version of the type of other is not T or derived from T, or if T is non-class type, but the type of other is a class type, user-defined conversion sequences that can convert from the type of other to T (or to a type derived from T if T is a class type and a conversion function is available) are examined and the best one is selected through overload resolution.

That means the conversion from C to std::string is examined, and used for the initialization here.

After C++17

Since C++17 for direct initlizatioin,

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)

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.

LIVE



来源:https://stackoverflow.com/questions/46740341/different-behavior-among-explicit-cast-direct-initialization-and-copy-initializ

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!