Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why would I need conversion?

Tags:

c++

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[])
{
    return 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?

like image 834
There is nothing we can do Avatar asked Sep 30 '10 18:09

There is nothing we can do


1 Answers

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
}
like image 181
John Dibling Avatar answered Oct 07 '22 06:10

John Dibling