Compiler error for conditional operator “?:” when

2019-03-26 00:15发布

问题:

Following code is in simplest form:

struct X {
  operator char () const { return 'a'; }
};

int main ()
{
  X obj, *p = &obj;
  char a = *p;  // ok
  char c = (true)? *p : 'z';
}

This code gives compiler error as,

error: operands to ?: have different types ‘X’ and ‘char’

Why *p is not resolved to char when there is no ambiguity in class X for typecasting operator ? Is such spurious error message correct or it's a g++ bug ?

[Update Note: Interestingly this scenario doesn't generate such error]

回答1:

It seems to be a compiler-bug. I checked it out in the spec, the Standard clearly says (§5.16/3 - C++03),

Otherwise, if the second and third operand have different types, and either has (possibly cv-qualified) class type, an attempt is made to convert each of those operands to the type of the other.

and the rest of the section explains how the conversion is done. There is nothing that stops *p from implicitly converting into char type, using the user-defined conversion operator.

Also, I compiled it with (GCC) 4.5.0. It gives no error, with -pedantic option as well. Tried it -std=c++98 and -std=c++0x. Still no error.

Most definitely, it is a compiler-bug.



回答2:

There are issues with implicit conversion between classes for the conditional operator ?: in certain versions of G++. Also depending on the version you may either see an error, or you may /not/ see such an errors, however all three of your samples are correctly flagged by G++.

This is less of an answer to the original question but a re-certification of the original poster's, and others', qualm that there might be problems with spurious errors with G++ compiler and the conversion behavior for class types as specified in ISOC++:2003 5.16/3 [expr.cond]/3 (also outlined above by @Nawaz)

One example that shows the converse of the original poster's sample where implicit conversion in both directions can happen but isn't flagged can be seen here.

I compiled this on G++ v3.4.6, v4.1.2, v4.2.1 and v4.5.0(windows) and saw no problems because as again @Nawaz said this is the correct behavior within the ISOC++:2003 spec.

However, when I followed the link on your IDEONE page the structure definition was different and that is the root of your error.

struct X
{
  char ch;
  X(const char c) : ch(c) {}

  operator char () const { return ch; }
};

int main ()
{
  X obj('a'), *p = &obj;
  char a = *p; // ok
  char c = (true)? *p : 'b';
}

Then as above the struct is different and I do get the error your see. This is a correct error as 'z' can be converted into X or char, and because of the constructor 'z' can also be converted into X - bi-directionality of X/'z' so the compiler should stop. However with a little change it can be made to pass and that is exactly the same bug as the GNU G++ bug posted above.

If you convert your sample above to a pointer sample it will fail. Character pointer, int pointer or whatever.

Although unrelated I thought it might be a good point to highlight something that often caught me out whilst cross-porting between Windows/Linux. MSVC will happily pass such conversions often if it deems the conversion to be "safe", or often it may proffer a warning that conversion is being done at the risk of loss of precision - I am not sure what the trigger for allowing this is.



回答3:

The error is correct. operands to ?: have different types: ‘X’ the first, and ‘char’ the second. The compiler cannot know that you want the expression to be a char in the end - that will happen later, after the evaluation of the whole expression (true)? *p : 'z'; - an evaluation which cannot be done in the first place due to type discrepancies.