Reputation: 4421
I have the following problem with inheritance and templates:
class Base {};
class Deriv : public Base {};
template <class T> class X{};
void f(X<Base>& inst) {}
int main()
{
X<Base> xb;
f(xb);
X<Deriv> xd;
f(xd);
return 0;
}
The program doesn't compile because there is not relation between X<Base>
and X<Deriv>
. Nevertheless I think it should be possible to do everything that can be done with X<Base>
also with X<Deriv>
. Is there anything that I could do other than copying the function body of f
to a new function void g(X<Deriv>& inst)
?
Upvotes: 2
Views: 199
Reputation: 75150
Why do you think they should be related? Consider the following:
template<typename T>
class X;
template<>
class X<Base> {
int x;
};
template<>
class X<Deriv> {
double d;
};
They're definitely not interchangeable. So no, there is no relation between those classes and you can't pass one to a function expecting the other. You'll have to do something like make both types inherit from another common type that exposes the interface you need.
Regarding your comment, you can use type traits and static_assert
to do what you would do in Java:
template<typename T>
void f(X<T>& inst) {
static_assert(std::is_base_of(Base, T)::value, "Template type must subclass Base");
// body of function...
}
Upvotes: 1
Reputation: 145429
It depends. Consider the case where X
is std::shared_ptr
. It would break type safety if std::shared_ptr<Derived>
was derived from std::shared_ptr<Base>
, but instead there is an implicit value conversion.
However, since you’re passing by reference to non-const
, such a value conversion will not help you you directly.
Other possibilities include inheriting from a common interface, and templating your function.
Upvotes: 0
Reputation: 208456
Different instantiations of a template are unrelated types, even if the instantiating template arguments are related. That is, X<A>
is not related to X<B>
regardless of what the relationship between A
and B
might be.
Now as of what can be done, it depends on what your template actually is. In some cases you can provide conversions so that the X<Derived>
can be converted to a X<Base>
for a particular operation. Another alternative is modifying your function to be able to take any X<T>
for which T
derives from Base
(this can be done by creating a template and using SFINAE to disallow calling it with T
s that don't derive from Base
. Again, depending on what your template is, you might be able to offer access to the underlying type, in which case the function could take a reference to Base
(consider shared_ptr
or unique_ptr
with the .get()
method)
Without a description of what you actually want to get done it is impossible to provide a good alternative.
Upvotes: 0
Reputation: 92381
You could just continue using templates:
template<class T>
void f(X<T>& inst) {}
will work for both X<Base>
and X<Derived>
.
The compiler might duplicate the code (if it is not smart enough), but you don't have to.
Upvotes: 2
Reputation: 147036
If you need such functionality, then you must template on the type- or overload, as you have said. Alternatively, you might explicitly specialize X
such that X<Derived> : X<Base>
.
Upvotes: 0