Casting pointers and the ternary ?: operator. Have I reinvented the wheel?

前端 未结 4 1578
无人共我
无人共我 2021-02-14 04:19

The last line of this code fails to compile with castingAndTernary.cpp:15: error: conditional expression between distinct pointer types ‘D1*’ and ‘D2*’ lacks a cast

相关标签:
4条回答
  • 2021-02-14 04:57

    I just came across this problem, lose the casts and do it the long way is cleanest IMO

    B * d1 = new D1();
    B * d2 = new D2();
    B * b = boolean_expression ? d1 : d2;
    
    0 讨论(0)
  • 2021-02-14 05:04

    The [ternary] conditional operator requires its second and third operands to have the same type.

    b = boolean_expression ? new D1 : new D2;
    

    You have the distinct types D1* and D2*. As the error message indicates, you have to ensure the correct type with an explicit conversion (i.e. a cast):

    b = boolean_expression ? static_cast<B*>(new D1) : static_cast<B*>(new D2);
    

    The standard says that compilers must require this (instead of just doing an implicit conversion), so that's what your compiler requires.

    0 讨论(0)
  • 2021-02-14 05:06

    A really smart compiler could have no difficulty because both can be safely casted to B*

    Irrelevant. The standard mandates this behaviour. A really smart compiler behaves as observed.

    The use of your custom cast is actually fine (and your reluctance for using an explicit cast is well-placed). However, I’d use a different name: upcast – since that’s happening here: a cast upwards in the inheritance hierarchy.

    0 讨论(0)
  • 2021-02-14 05:07

    I was not going to answer, but after posting the comment I thought, what the... it is an approach as any other:

    int main() {
       bool condition = true;
       D1 d1;
       D2 d2;
       B * p = condition ? &d1 : (true? &d2 : p );
    }
    

    Basically abuse the ternary operator to extract the appropriate type. When the compiler processes the ternary operator it tries to determine whether the two operands can be implicitly converted to a common type 1, and if so, it uses that common type as the type of the expression.

    In the code above, the inner ternary operator: true? &d2 : p will try to match the type of the expression &d2 with the type of p, it will find that there is a simple upcast that it can perform and will set the return type for that subexpression to B*. Note that because the condition is true, it will always yield &d2, even if it uses the third argument to determine the type.

    The same operation is performed with the enclosing expression, where now the second argument is &d1 (type D1*) and the type of the third argument is B*. Again, the conversion is trivial by upcasting D1*, and the type of the whole expression is B*.

    Because all of the conversions are performed implicitly by the compiler, if you change the types of the pointers, and break the invariant that they can be implicitly converted, the compiler will tell you, solving the issue of throwing a static_cast in the middle of the ternary operator.

    1 The standard dictates a set of different conversions, depending on the types of the arguments. In the particular case of the two arguments being pointers (as is the case here) the conversions that are allowed are pointer conversions and qualification conversions.

    0 讨论(0)
提交回复
热议问题