Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Different casting operators used by different compilers

The following C++ program compiles without warnings in all compilers I have tried (gcc 4.6.3, llvm 3.0, icc 13.1.1, SolarisStudio 12.1/12.3):

struct CClass
{
  template<class T>
  operator T() const { return 1; }

  operator int() const { return 2; }
};

int main(void)
{
  CClass x;
  return static_cast<char>(x);
}

However, all but the SolarisStudio compilers return 2, SolarisStudio (either version) returns 1, which I would consider the most logical result.

Using return x.operator char(); results in all compilers returning 1.

Obviously, since figuring this out, I have been using the latter notation. However, I would like to know which of compilers is correct and why. (One would think that majority rules, but this still doesn't explain the why.)

This question seems to be related to the SO questions here, here, and here, but these "only" give solutions to problems, no explanations (that I was able to apply to my particular problem anyway).

Note that adding an additional overloaded casting operator, say operator float() const { return 3; } results in all compilers except SolarisStudio complaining about ambiguity.

like image 504
Michael L. Flegel Avatar asked May 19 '13 14:05

Michael L. Flegel


People also ask

Which operator is used to casting types?

Cast operator: () A type cast provides a method for explicit conversion of the type of an object in a specific situation.

What are cast operators?

A Cast operator is an unary operator which forces one data type to be converted into another data type. C++ supports four types of casting: 1. Static Cast.

What are different types of casting in C++?

In order to control these types of conversions between classes, we have four specific casting operators: dynamic_cast, reinterpret_cast, static_cast and const_cast.


2 Answers

The first (template) overload should be picked.

Paragraph 13.3.3/1 of the C++11 Standard specifies:

[...] a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then

— for some argument j, ICSj(F1) is a better conversion sequence than ICSj(F2), or, if not that,

the context is an initialization by user-defined conversion (see 8.5, 13.3.1.5, and 13.3.1.6) and the standard conversion sequence from the return type of F1 to the destination type (i.e., the type of the entity being initialized) is a better conversion sequence than the standard conversion sequence from the return type of F2 to the destination type. [ Example:

struct A {
    A();
    operator int();
    operator double();
} a;
int i = a; // a.operator int() followed by no conversion
           // is better than a.operator double() followed by
           // a conversion to int
float x = a; // ambiguous: both possibilities require conversions,
             // and neither is better than the other

end example ] or, if not that,

F1 is a non-template function and F2 is a function template specialization, or, if not that,

[...]

As you can see the, fact that the first conversion operator is a template only becomes relevant when the standard conversion sequence from its return type (char, in this case) to the destination type (char, in this case) is not better than the standard conversion sequence from the return type of the non-template overload (int, in this case) to the destination type (char, in this case).

However, a standard conversion from char to char is an Exact Match, while a standard conversion from int to char is not. Therefore, the third item of § 13.3.3/1 does not apply, and the second item does.

This means that the first (template) overload should be picked.

like image 96
Andy Prowl Avatar answered Oct 06 '22 10:10

Andy Prowl


The first is an exact match, the second requires a conversion. Exact matches have priority over conversions.

Those other questions you linked are mostly unrelated to yours.

Some advice: don't use template conversion operators. Name it convert_to instead.

like image 41
Pubby Avatar answered Oct 06 '22 09:10

Pubby