Greetings all.
I am writing some code using the Boost Units library and have run into a problem.
I have managed to abstract the problem from Boost code so you won't be looking through reams of boost template meta programming. Though I'm sure if you have experience with that it could help. Here is the reproduction:
class Base{};
class Derived : public Base
{
public:
Derived(){}
Derived(const Base &){}
};
class Q {};
class U
{
public:
template< typename Y >
Q operator * (Y)
{
Q r;
return r;
}
};
Base operator * (U, const Base &)
{
Base r;
return r;
}
int main(int argc, char **argv)
{
Base myBase;
U myU;
Base myOtherBase = myU * myBase;
Derived myDerived;
Derived myOtherDerived = myU * myDerived;
return 0;
}
So the problem (specifically) is as follows: myU * myBase
uses operator * (U, const Base &)
and returns type of Base
, all good so far. Whereas myU * myDerived
insists on using generalised U::operator * (Y)
and hence returns a Q
, no good because I wanted a Base
again.
Now, all classes other than Base
and Derived
are boost library classes so I cannot modify the members of U. How do I "beat" U::operator * (Y)
for overload/template deduction/instantiation, in this case, in an elegant and "solved once and for ever" manner.
I am using MSVC++ 2008 in case it is relevant to anyone.
Edit: Added a possible (quite likely) solution in answers
Using the following should fix your problem
Base myOtherDerived = myU * (Base&)myDerived;
// or
Base myOtherDerived = myU * static_cast<Base&>(myDerived);
instead of
Derived myOtherDerived = myU * myDerived;
This is not what we could call a "clean solution" though. I'm trying to find a better way to do it.
First, the problem: The const Base&
parameter of the operator*
will always be a worse fit than the template parameter's exact fit because of conversion from Derived
to Base
.
Next, the solution: Provide overloaded operator*
for every derived class. :(
If you have control over the ordering of the operators, you could define your operator*
in the opposite direction, i.e.,
Base operator* (const Base& lhs, U rhs)
{
Base r;
return r;
}
Now if you tried
Derived myOtherDerived = myDerived * myU;
it would not fit the template in class U
, getting you around the issue of the template function in U
overriding your own operator*
function.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With