Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 e.g. 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

like image 488
Bernd Avatar asked Oct 22 '19 21:10

Bernd


People also ask

Can static_cast fail?

As we learnt in the generic types example, static_cast<> will fail if you try to cast an object to another unrelated class, while reinterpret_cast<> will always succeed by "cheating" the compiler to believe that the object is really that unrelated class.

What happens when you perform a static_cast?

Static Cast: This is the simplest type of cast which can be used. It is a compile time cast.It does things like implicit conversions between types (such as int to float, or pointer to void*), and it can also call explicit conversion functions (or implicit ones).

How does static_cast int work?

The static_cast operator converts variable j to type float . This allows the compiler to generate a division with an answer of type float . All static_cast operators resolve at compile time and do not remove any const or volatile modifiers.

What is the difference between static_cast and Dynamic_cast?

static_cast − This is used for the normal/ordinary type conversion. This is also the cast responsible for implicit type coersion and can also be called explicitly. You should use it in cases like converting float to int, char to int, etc. dynamic_cast −This cast is used for handling polymorphism.


1 Answers

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.

like image 153
Davis Herring Avatar answered Oct 07 '22 13:10

Davis Herring