开发者

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>;
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜