C++ covariant templates
Both the copy constructor and the assignment operator should be able to take a SmartPtr of a different type and attempt to copy the pointer from one to the other. If the types aren't compatible, the compiler will complain, and if they are compatible, you've solved your problem. Something like this:
template<class Type> class SmartPtr
{
....
template<class OtherType> SmartPtr(const SmartPtr<OtherType> &blah) // same logic as the SmartPtr<Type> copy constructor
template<class OtherType> SmartPtr<Type> &operator=(const SmartPtr<OtherType> &blah) // same logic as the SmartPtr<Type> assignment operator
};
C++ Template Covariance
Given the reference to an earlier question as a clarification device, it seems you are asking why T<Derived>
is not usually derived from T<Base>
.
Consider T
= std::shared_ptr
.
You don't want to be able to do this:
void foo( shared_ptr<Base>& p ) { p.reset( new Derived2 ); }
auto main() -> int
{
shared_ptr<Derived1> p;
foo( p ); // Oops, p now points to unrelated Derived2
}
C++ Templates, Polymorphism, and Template Covariance
If each class reports its base:
class A {
using Base = void;
// things
}
class B : public A {
using Base = A;
// more things
}
You could do
template<typename T>
class Wrapper : public EmptyForVoid<T::Base>::Type
And use EmptyForVoid
for the base class selection:
template<typename T>
struct EmptyForVoid { using Type = T; };
template<>
struct EmptyForVoid<void> { struct Type {}; };
This will make Wrapper
s follow the same inheritance tree as the types they wrap.
Specifying covariant/contravariant behavior with C++ templates
In C++, like in other OO languages, subtypes are generally represented by inheritance.
However, we cannot model covariance and contravariance relationships through inheritance, because there is no way to list the base classes of a class (without any of the various reflection proposals, which have not made their way into the language yet).
The easiest way to allow this kind of behavior is to allow covariant and contravariant templated classes to convert based on the relationship of the related types.
Covariance
If
Derived
is-aBase
, thenCovariant<Derived>
"should-be-a"Covariant<Base>
.
Normally, the solution would be to make Covariant<Derived>
inherit from Covariant<Base>
, but we currently have no way of finding Base
given only Derived
. However, we can enable the conversion by writing a constructor for Covariant<Base>
taking any Covariant<Derived>
:
template <typename T>
struct Covariant {
template <typename Derived>
Covariant(const Covariant<Derived>& derived,
std::enable_if_t<std::is_base_of_v<T, Derived>>* = nullptr)
{
/* Do your conversion here */
}
};
Contravariance
If
Derived
is-aBase
, thenContravariant<Base>
"should-be-a"Contravariant<Derived>
The trick here is much the same - allowing the conversion of any Contravariant<Base>
to Contravariant<Derived>
:
template <typename T>
struct Contravariant {
template <typename Base>
Contravariant(const Contravariant<Base>& base,
std::enable_if_t<std::is_base_of_v<Base, T>>* = nullptr)
{
/* Do your conversion here */
}
};
However
This has one major drawback: You need to implement the conversions manually, and be aware that accidental object slicing may ruin your ability to convert back (e.g. if you define a covariant container type, that will be a cause of major headaches).
Essentially, until reflection allows us to automate that sort of inheritance relationship, conversions are the only way to do this, and I would not recommend using this for anything complex. As soon as you store objects of your T
in the covariant/contravariant classes, you are in for a world of hurt.
Here is a Godbolt link to show that it works
Correct way to define a covariant template function in C++
Depends on the check you actually want to do.
To check for a public, unambiguous base, use is_convertible
on pointers:
template <class T>
auto foo(T& x) -> std::enable_if_t<std::is_convertible<T*, A*>{}/*, void*/> {
// stuff
}
To check for any base whatsoever, public, protected or private, ambiguous or unambiguous, use is_base_of
:
template <class T>
auto foo(T& x) -> std::enable_if_t<std::is_base_of<A, T>{}/*, void*/> {
// stuff
}
c++ template covariance polymorphism
A simple technical solution is to parameterise the concrete factory with the desired base, like this:
template <class C, class C_base = C>
class NormalFactory:public Factory<C_base>{
public:
C* create(){return new C;}
};
Example at Coliru.
However, the design doesn't feel right somehow. I suggest thinking about what the factories are meant to accomplish, and if there's any other more natural way of accomplishing that in C++. I.e., I think this is an XY-question.
C++ containers, covariance and template
You can let Derived::getData(
) return QVector<Data*>
. When you need to use it, find out if the pointers in QVector
is to Data
or DerivedData
, using dynamic_cast
or similar method.
How to implement template class covariance in C++?
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).
Related Topics
Undefined Symbols for Architecture X86_64: Which Architecture Should I Use
How Many Decimal Places Does the Primitive Float and Double Support
Why Are C++ Int and Long Types Both 4 Bytes
Sse2 Intrinsics - Comparing Unsigned Integers
How to Implement Tesseract to Run with Project in Visual Studio 2010
Are Data Members Allocated in the Same Memory Space as Their Objects in C++
Vector of Class Without Default Constructor
Simple For() Loop Benchmark Takes the Same Time with Any Loop Bound
#Error Please Use the /Md Switch for _Afxdll Builds
Convert Shared Library to Static Library
How to Show Qsqlquerymodel in Qml
How to Write an Agile Pimpl in C++
What Does *& Mean in a Function Parameter
How to Initialize a Struct to 0 in C++
How to Implement Readlink to Find the Path