简体   繁体   中英

static_cast : Conversion function templates - are they really working?

As far as I read static_cast the following code should work:

#include <iostream>
#include <string>

class ConvSample
{
public:
    template<typename T>
    constexpr operator T(){
        return {};
    }
};

int main()
{
    ConvSample aInst;

    int i = aInst;
    std::cout << i << "\n";

    std::string str = static_cast<std::string>(aInst);
    std::cout << str << "\n";

    return 0;
}

And it works perfectly with some compilers like Clang. But eg with MSVC or ICC not.

See Compiler Explorer

In general they complain about some ambiguity caused by not really working constructors provided by std::string.

In addition if I turn on Wconversion on gcc I get a segmentation fault?!

Is there something wrong in the code? Are these errors just compiler bugs? If I change the code to not use templates it workes very well: Compiler Explorer

The standard is unfortunately vague here ([expr.static.cast]/4, citations omitted):

An expression e can be explicitly converted to a type T if there is an implicit conversion sequence from e to T , or if overload resolution for a direct-initialization of an object or reference of type T from e would find at least one viable function. […] [T]he result object is direct-initialized from e . […]

Both of the enabling conditions hold here: there is an implicit conversion sequence (consisting of the desired conversion function call), and there are several viable functions for direct-initialization (because there are also implicit conversion sequences for the various single parameters for std::string constructors).

However, it is only the copy-initialization of the implicit conversion sequence, which refuses to convert ConvSample to (say) const char* and then to std::string , that provides an unambiguous means of producing a std::string : it specifically looks for conversion functions to the target type, and while it allows conversions to (say) const std::string& , common implementations do not interpret that to mean that the conversion function template should be instantiated for that type as well and become ambiguous.

The direct-initialization that is ultimately called for is ambiguous among std::string 's 5 single-argument constructors (6 for std::string_view -like types): ConvSample can of course be converted to the parameter type for any of them at the same “cost”.

The compilers that accept this are applying copy-initialization rules (but still allowing explicit conversions). Those that reject it are applying direct-initialization, which I believe is what the wording currently requires. The reference to implicit conversion sequences was introduced only in C++17 for CWG242 , and apparently implementation divergence persists in this area.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM