Template and inheritance - c++

If I have a base class and its hierarchy :
class BaseClass {
}
class DerivedClass : public BaseClass {
}
And a templated class :
template <class T> struct TemplatedClass {
}
How can I achieve this ? :
// 1:
void doSomething(TemplatedClass<BaseClass *> const &t);
// 2:
std::vector<TemplatedClass<BaseClass *>> v;
TemplatedClass<DerivedClass *> a;
// Doesn't compile
doSomething(a);
// Doesn't compile
v.push_back(a);

You could have your templated classes have a hierarchy, too. You'll need to specify the bases, however:
template <typename...>
struct TC;
template <>
struct TC<> {
virtual ~TC() {}
};
template <typename T, typename... B>
struct TC
: TC<B...> {
// ...
};
With the variadic argument for the inheritance this should allow you specifying the relationship between the templates to mimick the inheritance hierarchy of the underlying. For example:
TC<Base>* d = new TC<Derived, Base>(/*...*/);

You need to make TemplatedClass<DerivedClass*> convertable to TemplatedClass<BaseClass *>, as they are independent types. Best way would be to have constructor, something like this:
template <class T> struct TemplatedClass {
template<class P> TemplatedClass( const TemplatedClass<P> &an );
};
Looks like you are trying to make something like smart pointer, you should look how it is already done on std::shared_ptr or boost::shared_ptr.
If you plan to use this code in production and/or share it with your team you may want to put additional checks on data type passed to this ctor:
template <class T> struct TemplatedClass {
template<class P, class = typename std::enable_if<std::is_convertible<P, T>{}>::type>
TemplatedClass( const TemplatedClass<P> &an );
};
Again best way would be to look into sources of shared_ptr and see how it is done there.

Related

What is the right way to implement this templated decorator pattern for this situation?

template <typename T> class FooBase {
void push(T& t) = 0;
T pop() = 0;
}
template<typename T> class FooDerived1: public FooBase<T> {
}
template<typename T> class FooDerived2: public FooBase<T> {
}
////////////////////////////////
template<typename T, typename Foo> class Bar: public Foo<pair<T, int>> {
void push(T& t) {
int value = get_val();
foo_.push(make_pair(t, v));
}
pair<T, int> pop() {
return foo_.pop();
}
Foo<pair<T, int>> foo_;
}
So basically we have different instances of class Foo, "FooDerived1", "FooDerived2" etc
We have a class Bar, which is a decorator, on top of class Foo, which should take in different any children of class Foo.
The problem is that, the decorator would initialize class FooBase's template with a modified typename. Basically change FooBase to FooBase<pair<T, int>>
Inside class Bar, I would use all of Foo's interface, and also a wrapper, around the base class function
What is the right way to do this? Because when I am trying to initialize class Bar, I am confused.
Bar<float, FooDerived1<float>> bar1;
Bar<float, FooDerived2<float>> bar2;
I am not sure how this would work and what is the right way to accomplish, what I am trying to do.
Thank you.
First, Bar needs only a single template argument. T can be deduced from an instantiation FooBase<T> via a type trait, or by using a member alias.
Then you can use SFINAE to check if that argument inherits from FooBase (which adds a second argument again):
#include <type_traits>
#include <utility>
template <typename T> struct FooBase { using type = T; };
template <typename T> struct Foo1 : FooBase<T> {};
template <typename T,typename = void> struct Bar;
template <typename T>
struct Bar< T,
std::enable_if_t<
std::is_base_of_v<
FooBase<typename T::type>,T>>
>
: FooBase<std::pair<typename T::type,int>> {};
int main() {
Bar< Foo1<int>> c;
}
Though, this would be much simpler if you drop some restrictions. If Bar<T> does not require T to inherit from FooBase and if the caller instantiates it via Bar< sometype::type > then no SFINAE is needed and Bar could be simply template <typename T> struct Bar : FooBase<std::pair<T,int>> {};. Also it is not clear what is the relevance of the derived class for Bar. In your code Bar merely uses T and FooBase. However, I hope the above will help.

C++ template which returns a different derived class based on template argument integer

I can't quite figure out the right pattern or idiom to do this, so I would appreciate suggestions.
Right now I have a pure virtual base class
template<typename T, int size>
class Base {
public:
virtual Eigen::Matrix<T, x_size, 1>
doSomething(const Eigen::Matrix<T, x_size, 1> &x) = 0;
...
and I have some derived classes with different values for the size template parameter. For instance,
template<typename T>
class Accelerometer : public Base<T, 4> { ...
template<typename T>
class Gyroscope : public Base<T, 5> { ...
There are many such classes. They are all quite different.
EDIT: I do not want to rename the classes, since doing to would make the code very confusing to read.
Elsewhere in the code, I have a class which holds a reference to a Base class object:
template<typename T, int size>
class Other {
private:
Base<T, size> &base;
public:
Other(Base<T, size> &base) : base(base) {...
So, for instance, I could say something like
Other<T, 4> other4( Derived4<T>() );
Other<T, 5> other5( Derived5<T>() );
However, in my main code, I only need one Other instance. Ideally, I would like to do something like this:
const int size = 4;
// TODO Initialize `other` with appropriate derived class.
Other<T,size> other( getDerived<size>() )
where the getDerived function would return the Derived class of the appropriate size. I can't figure out how to define such a function. My first thought was to do something like this:
template<int size>
Base<size> getDerived() {
return NULL;
}
However, that won't work because the Base class is a pure virtual.
Next, I thought of perhaps doing some specialization of the template function
template<DerivedType>
DerivedType getDerived() {
return NULL;
}
However, that is dumb because then I explicitly would have to state the class when calling the getDerived function.
So I feel like either I am missing something simple, or the entire approach I am using is wrong. Do you guys have any suggestions?
You can use template partial specialization instead of hardcoding the number into the class Derived4, Derived5's name:
template<class T, int N> struct Base {};
template<class T, int N> struct Derived;
template<class T>
struct Derived<T, 4> : public Base<T, 4> {
/* for Derived4 */
};
template<class T>
struct Derived<T, 5> : public Base<T, 5> {
/* for Derived5 */
};
template<class T, int N>
Derived<T, N> getDerived();
EDIT:
If you want class name to be descriptive, you can always use using alias, for example:
template<class T> using Accelerometer = Derived<T, 4>;
template<class T> using Gyroscope = Derived<T, 5>;

Remove redundant template types

I am currently struggling with templates: I have a templated class A, which performs basic math (for floats, doubles, complex numbers) and looks like this
template <typename T>
class A
{
public:
void foo(std::vector<std::complex<T>>& result);
};
Now I can use the class like A<double>, A<float>, but I would also like to use it like A<std::complex<float>> and A<std::complex<double>>. When using the latter, I would like the definition of foo to look like
void foo(std::vector<std::complex<float>>& result);
and not like
void foo(std::vector<std::complex<std::complex<float>>>& result);
Is there any way to create a specific template for the std::complex<T> cases, in which I can access the "inner" type? Or this is not possible/bad practice?
What is the most elegant way to solve this issue?
Another way can pass through the creation of a type traits to detect the (extract, when needed) the float type
template <typename T>
struct getFloatType
{ using type = T; };
template <typename T>
struct getFloatType<std::complex<T>>
{ using type = T; };
and use it in A (see fT)
template <typename T>
class A
{
public:
using fT = typename getFloatType<T>::type;
void foo(std::vector<std::complex<fT>>& result)
{ }
};
You can make a partial specialization for any instantiation of std::complex, e.g.
template <typename T>
class A<std::complex<T>>
{
public:
void foo(std::vector<std::complex<T>>& result);
};
Then for A<std::complex<double>>, the signature of foo would be void foo(std::vector<std::complex<double>>& result);.
To handle those duplicated codes, you can make a base class and move the common members into it, and make the primary template and partial specialization both derive from it. e.g.
class Base {
public:
void bar(...);
};
then
template <typename T>
class A : public Base {
...
};
template <typename T>
class A<std::complex<T>> : public Base {
...
};

Using template class with the incomplete type void

I have the following template class :
template <typename T>
class myClass
{
public:
// Many methods...
protected:
private:
T attribute
// Other attributes.
};
Instantiating an object of type myClass<void> does not work, because of void attribute.
Can you give me some hints to be able to use objects of type myClass<void> without specializing the whole class. Since it has many member functions that rely on the type T, specializing it will lead to code duplication.
Create a templated base class containing attribute, specialize it for void and inherit from it:
namespace detail //Warn end user that he should not use stuff from here
{
template <typename T>
struct myClass_base
{
T attribute;
};
template <>
struct myClass_base<void>
{}; //No attribute at all
}
template <typename T>
class myClass: private detail::myClass_base<T>
{
//rest of definition
};
This would make myClass lack attribute field when instantiating it with type void
You can defer the whole problem by using a custom type and specializing that:
template<typename T>
struct my_type_t
{
using type = T;
};
template<>
struct my_type_t<void>
{};
template<typename T>
using my_type = typename my_type_t<T>::type;
template <typename T>
class myClass
{
public:
// Many methods...
protected:
private:
my_type<T> attribute
// Other attributes.
};
Then at least you don't have to duplicate the whole rest of the class again.
But it probably does not make that much sense, as you surely want to use the type somewhere. So you would have to specialize that places further.

Templated deriving from a template

Given two templated classes which are very similar but behave differently:
template<class T>
firstBase {};
template<class T>
secondBase {};
Now I've got this other class, which, based on it's template parameter, will derive either from firstBase or from secondBase:
template<class B, class T>
myClass : public B<T> { /* T is used in here */ };
Well, that does not work. The compiler tells me that B is an unknown template name. (error: unknown template name 'B')
My current workaround is to define myClass as
template<class B, class T>
myClass : public B { /* T is used in here */ };
and the caller of myClass needs to intatiate it via myClass<b<t>, t> instead of myClass<b, t>.
The latter would be really nice and reduce some copy&paste code. Is there any other way of achieving this?
In my use case I'm trying to implement a deep_const_ptr for the pimpl idiom enabling 'true constness'. Depending on whether myClass needs to be copy-assignable or not, it either uses deep_const_ptr<std::shared_ptr> or deep_const_ptr<std::unique_ptr> for its private pointer.
#include <memory>
#include <iostream>
template<class pointerT, class typeT>
class deep_const_ptr : public pointerT
{
public:
explicit deep_const_ptr(typeT* ptr) : pointerT(ptr) { }
// overloading pointerT::operator->() for non-constant access
typeT* operator->() {
std::cout << "deep_const_ptr::operator->()" << std::endl;
return pointerT::operator->();
}
// overloading pointerT::operator->() for constant access
const typeT* operator->() const {
std::cout << "deep_const_ptr::operator->() const" << std::endl;
return pointerT::operator->();
}
};
Edit
So I ended up, as suggested by Luc Danton in his answer, passing std::unique_ptr<myClass::Private> or std::shared_ptr<myClass::Private> to my custom deep_const_ptr:
template<typename pointerTypeT>
class deep_const_ptr : public pointerTypeT {
explicit deep_const_ptr(typename pointerTypeT::element_type* ptr) : pointerTypeT(ptr);
typename pointerTypeT::element_type* operator->();
const typename pointerTypeT::element_type* operator->() const;
};
deep_const_ptr<std::unique_ptr<Test::Private>> d_unique;
deep_const_ptr<std::shared_ptr<Test::Private>> d_shared;
What you want is template template parameter:
// vvvvvvvvvvvvvvvvvv
template<template<typename> class B, class T>
class myClass : public B<T> { /* T is used in here */ };
Then, use that like:
myClass<firstBase,int> myIntClassObject;
myClass<secondBase,bool> myBoolClassObject;
For std::unique_ptr, you can make a wrapper:
template<typename T>
class uniquePtr : public std::unique_ptr<T>
{
};
or
template<typename T>
using uniquePtr = std::unique_ptr<T>;
I recommend against template template parameters in general. For instance std::unique_ptr and std::shared_ptr are different in that the former accepts two type parameters and the latter just one. So if you declare e.g. template<template<typename> class B, typename T> class foo; then foo<std::shared_ptr, int> is valid but foo<std::unique_ptr, int> isn't.
In your particular case you could use template<typename...> class B as a parameter, because that kind of template template parameters is special. Still, this would only accept templates that only take type parameters (not even template template parameters). Sometimes this can be worked around with alias templates, sometimes it can't.
In my experience there are better alternatives -- for instance you can conditionally inherit:
template<typename T>
struct pointer: std::conditional</* Make a choice here*/, std::unique_ptr<T>, std::shared_ptr<T>>::type {};
Or why not just accept the smart pointer as the parameter itself:
template<typename Pointer>
struct foo {
Pointer pointer;
/* typename Pointer::element_type plays the role that T used to have */
};
The Standard Library itself takes some steps to avoid template template parameters: have you ever noticed that an std::vector<T> uses std::allocator<T> as an argument, and not std::allocator? As a tradeoff, it means that an Allocator must provide a rebind member alias template.
B should be a template template parameter:
template<template <class> class B, class T>
class myClass : public B<T> { /* T is used in here */ };
Now you can give either firstBase or secondBase as the first template argument because they are templates.
You simply need to use a template-template parameter to get it to work:
template <
template <class> class B, class T>
// ^^^^^^^^^^^^^^^^
class myClass : public B<T> { / ... / };
It seems what you need is template template parameters:
template<template<class> class B, class T>
// ^^^^^^^^^^^^^^^
class myClass : public B<T> { /* T is used in here */ };
Now the first template argument for the myClass class template must be itself a class template that accepts one template (type) parameter. So, putting everything together:
template<class T>
class firstBase {};
template<class T>
class secondBase {};
template<template<class> class B, class T>
class myClass : public B<T> { /* T is used in here */ };
And here is how you would instantiate your myclass template to create a class that derives from firstBase<int>:
myClass<firstBase, int> obj;
Finally, here is a live example.