Why would I need conversion?
In this code:
template<class T>
struct Side
{
};
template<class T>
struct LeftSide : public Side<T>
{
};
template<class T>
struct RightSide : public Side<T>
{
};
Side<int>* f(int left, int right)
{
return left < right ? new LeftSide<int> : new RightSide<int>;//<---Here I'm returning either left or right side
}
int _tmain(int argc, _TCHAR* argv[])
{
ret开发者_运维知识库urn 0;
}
I'm getting an error:
_Error 1 error C2446: ':' : no conversion from 'RightSide *' to 'LeftSide *'_I've thought (wrongly as I see) that I can assign pointer from derived to base without any problems. So where is the problem?
The problem is not with the conversion from either LeftSide
or RightSide
to Side<T>
. As you originally thought, this conversion would be fine.
Rather, the problem is with this expression:
left < right ? new LeftSide<int> : new RightSide<int>
Let's break this down a little. The ternary operator (properly referred to in the Standard as the 'comparison operator') looks like this:
bool_val ? lhs_expression : rhs_expression
Keep in mind that this whole construct is itself an expression. Meaning it returns a value, which has to have a type, obv. The type of the whole expression is deduced from the types of lhs_expression
and rhs_expression
. In this case, you have a LeftSide
and a RightSide
. So, here's your problem.
LeftSide
and RightSide
are not directly related to each other other than having a common base class, and there's no conversion available between them. (You'd have to write one.) So there's no single datatype that the bool_val ? lhs_expression : rhs_expression
can have. You might think, "well, silly compiler, why not just figure out the common base class and use that?" This is, indeed, a bit of a pain. Leaving the argument of it being Right or Wrong aside, it just doesn't work that way.
You have two options.
One, use a simpler construct:
if( left < right )
return new LeftSide<int>;
else
return new RightSide<int>;
Two, if you really really want to use the ternary operator (which is the case sometimes), you need to spoon-feed the compiler it's datatypes:
Side<int>* f(int left, int right)
{
return left < right ? static_cast<Side<int>*>(new LeftSide<int>) : static_cast<Side<int>*>(new RightSide<int>);// now you're good
}
I think that the ? : operator requires that the 2 choices be the same type; not that they can be converted to the same type
FYI gcc fails the same
error: conditional expression between distinct pointer types ‘LeftSide<int>*’ and ‘RightSide<int>*’ lacks a cast
casting both to Side(int)* works (but you probably knew that already)
You want both branches to return a Side<int>*
, but the compiler doesn't know that, the type Side<int>
doesn't appear anywhere in that expression.
Since I don't like to use a cast when an implicit conversion exists, I'd write this as:
if (left < right) return new LeftSide<int>;
return new RightSide<int>;
But if you want to use a ternary operator,
Side<int>* i_want_this_type;
return (left < right) ? new LeftSide<int> : (i_want_this_type = new RightSide<int>);
Now the right hand branch is type Side<int>*
, the left hand is convertible to that type, everything is ok (and the compiler optimizes out the extra variable).
The two should be the same type, or one should be convertible to the other.
return left < right ? (Side<int>*)new LeftSide<int> : (Side<int>*)new RightSide<int>;
精彩评论