Reputation: 33
Is it possible to implement a class template in such a way that one object could be casted to another if their template arguments are related? Here is an exaple to show the idea (of course it will not compile):
struct Base {};
struct Derived : Base {};
template <typename T> class Foo {
virtual ~Foo() {}
virtual T* some_function() = 0;
};
Foo<Derived>* derived = ...;
Foo<Base>* base = derived;
The additional problem here is that Foo is an abstract class used as an interface containing functions returning T& and T*, so I can't implement a template copy constructor.
I'm writing a universal Iterator class which can hold any STL iterator, and in addition to type erasure I'd like it to be polymorphic, i.e. I could write something like this:
std::list<Derived> l;
MyIterator<Base> it(l.begin());
UPD: That was my mistake, I didn't actually need casting Foo* to Foo* to implement MyIterator, so I think the question is not actual anymore.
Upvotes: 2
Views: 3206
Reputation: 506847
The template argument has nothing to do with the content of the object you are pointing to. There is no reason this should work. To illustrate
struct Base { };
struct Derived : Base {};
template<typename T> struct A { int foo; };
template<> struct A<Base> { int foo; int bar; };
A<Derived> a;
A<Base> *b = &a; // assume this would work
b->bar = 0; // oops!
You will eventually access integer bar
that doesn't really exist in a
!
OK, now that you provided some more information, it's clear you want to do something completely different. Here is some starter:
template<typename T>
struct MyIterator : std::iterator<...> {
MyIterator():ibase() { }
template<typename U>
MyIterator(U u):ibase(new Impl<U>(u)) { }
MyIterator(MyIterator const& a):ibase(a.ibase->clone())
MyIterator &operator=(MyIterator m) {
m.ibase.swap(ibase);
return *this;
}
MyIterator &operator++() { ibase->inc(); return *this; }
MyIterator &operator--() { ibase->dec(); return *this; }
T &operator*() { return ibase->deref(); }
// ...
private:
struct IBase {
virtual ~IBase() { }
virtual T &deref() = 0;
virtual void inc() = 0;
virtual void dec() = 0;
// ...
virtual IBase *clone() = 0;
};
template<typename U>
struct Impl : IBase {
Impl(U u):u(u) { }
virtual T &deref() { return *u; }
virtual void inc() { ++u; }
virtual void dec() { --u; }
virtual IBase *clone() { return new Impl(*this); }
U u;
};
boost::scoped_ptr<IBase> ibase;
};
Then you can use it as
MyIterator<Base> it(l.begin());
++it;
Base &b = *it;
You may want to look into any_iterator
. With a bit of luck, you can use that template for your purpose (I haven't tested it).
Upvotes: 4
Reputation: 40336
While the other answers have pointed that this kind of relationship isn't "built-in" with templates, you should note that it is possible to build functionality to work with this sort of relationship. For example, boost::shared_dynamic_cast
and friends given
class A { ... };
class B : public A { ... };
let you cast between boost::shared_ptr<A>
and boost::shared_ptr<B>
.
Note that if you do go about implementing something like this, you'll have to be careful about the operations that MyIterator supports. For example, using your example of MyIterator<Base>(std::list<Derived>::iterator)
, you should not have an lvalue version of operator*()
, eg,
*myIter = someBaseValue;
should not compile.
Upvotes: 4
Reputation: 26060
Foo<Derived>
doesn't inherit Foo<Base>
, so you can't convert the former to the latter. Also, your assumption is wrong: dynamic_cast
will fail.
You could create a new object of instance of Foo<Base>
that copies your Foo<Derived>
instance, but I guess this is now what you're looking for.
Upvotes: 1