Domanda

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.

È stato utile?

Soluzione

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.

Altri suggerimenti

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top