So I have a simple template class with multiple classes inheriting different types of it.
template<typename T> class root {
T value;
};
class body : public root<int> {
/* some code */
};
/*some more classes that inherits root*/
and later down in the file, I need to reference all classes that inherits from root
concept _bcie = std::is_base_of_v<root, body>
and it gives me the error use of class template 'root' requires template arguments
But I want to reference ALL classes that inherits from the root
Is there a way to just use the class without providing a template argument?
Make root derive from another higher non-template base class, and check against that class.
The simple way is to use template lambda
template<typename T>
class root {
T value;
};
template<class T>
concept is_derived_from_root = requires (const T& t) {
[]<class U>(const root<U>&){}(t);
};
Demo
Related
How can I specify template parameter to be of a certain type i-e it must have implemented an interface (the template parameter must be a derived class of a specific base class)
Heres the interface (abstract base class)
class baseActionCounter{
public:
virtual int eat()=0;
virtual int drink()=0;
};
Now I want my template parameter to be of type baseActionCounter
Heres the templated class
//imaginary template syntax in the line below. Is there a way of achieving this behavior?
template <class counterType : baseActionCounter>
class bigBoss{
counterType counter;
public:
int consumerStats(){
//I am able to call member function because I know that counter object has eat() and drink()
//because it implemented baseActionCounter abstract class
return counter.eat() + counter.drink();
}
};
I can also just derive my bigBoss class from baseActionCounter but I want to know how to achieve this behavior with templates.
Also, template specialization is not suitable as there is just one BigBoss class for any implementor of baseActionCounter class.
Yes, you can use std::is_base_of to check the type, e.g.
template <class counterType, std::enable_if_t<std::is_base_of_v<baseActionCounter, counterType>>* = nullptr>
class bigBoss {
Or
template <class counterType>
class bigBoss {
static_assert(std::is_base_of_v<baseActionCounter, counterType>, "counterType must derive from baseActionCounter");
...
};
Or use concept (since C++20).
template <class T>
concept Derived = std::is_base_of_v<baseActionCounter, T>;
template <Derived counterType>
class bigBoss {
BTW: std::is_base_of also returns true if the base class baseActionCounter is specified; if that's not what you want you can combine the condition with std::is_same.
Note: The following question is about the Template Method Design Pattern and C++ function templates. To distinguish both, I will use italics when referring to the design pattern and bold when referring to C++ templates.
The idea of the template method pattern is to make parts of an algorithm exchangeable. This is usually achieved via inheritance, where the subclass provides concrete implementations that are plugged into an algorithm of the base class. However, if the hook methods need to be templates, this will not work as templates cannot be virtual. Here is a simple example that does not compile:
class Base
{
public:
// This is the template method
template <typename T>
void doSomething(T input)
{
//...
auto converted = ConvertInput(input);
//...
std::cout << converted;
}
protected:
//compile error "member function templates cannot be virtual"
template <typename T>
virtual T ConvertInput(T input) = 0;
};
class Derived : public Base
{
protected:
template <typename T>
T ConvertInput(T input)
{
return 2 * input;
}
};
int main()
{
Derived d;
d.doSomething(3);
}
Is there a way to implement template methods that use function template hooks?
I am not interested in using the Base class as a type anywhere. I will always use the concrete specific type to achieve a maximum of compile-time optimization. So another formulation of this question is: How can I create several classes Derived-1 .. Derived-n that have function templates that share a common code skeleton across the implementations?
Sounds like a fine use-case for CRTP. Define Base as a class template with the type derived from it as the template parameter. Inside Base's methods you can cast down to the derived type:
template<typename Derived>
struct Base
{
// This is the template method
template <typename T>
void doSomething(T input)
{
//...
auto converted = static_cast<Derived*>(this)->ConvertInput(input);
//...
std::cout << converted << std::endl;
}
};
And then define the derived types, for example:
struct Square : Base<Square>
{
template<typename T>
auto ConvertInput(T t)
{
return t*t;
}
};
struct Sum : Base<Sum>
{
template<typename T>
auto ConvertInput(T t)
{
return t+t;
}
};
the usage is pretty trivial:
Square sq;
Sum sum;
sq.doSomething(3);
sum.doSomething(3);
live demo
CRTP solves your problem by making Base a template.
If T comes from a finite set, or conversion is non arbutrary, type erasure can work.
If a finite set, type erase all the derived virtual methods. If common property, type erase that property and virtualize method that acts on it. Or a mixture.
Otherwise, Base can have template methods that take the operation as function object (with template operator()) instead of using virtual to find it. Derived passes the templated operations in as arguments to Base method(s). This is basically CRTP without CRTP.
I am thinking about using curiously recurring template pattern for my application. However, I would like the classes to operate on the user defined types. I would like to understand if it is possible to create a structure similar to the one shown below:
template <class T_leaftype>
class BaseTrajectoryPoint {
};
template <class MyType>
class MyTrajectoryPoint: public BaseTrajectoryPoint<MyTrajectoryPoint> {
private:
MyType A;
};
The code above fails to compile with the following error:
type/value mismatch at argument 1 in template parameter list for ‘template class BaseTrajectoryPoint’
Are there any alternative ways of approaching the problem? I would like to use static polymorphism, but I would prefer to define all possible methods in the base class.
template <class T_leaftype>
class BaseTrajectoryPoint {
};
template <class MyType>
class MyTrajectoryPoint: public BaseTrajectoryPoint<MyTrajectoryPoint<MyType> > {
private:
MyType A;
};
MyTrajectoryPoint isn't a type, it's template; when you pass it as template parameter, it's seen as template<typename> class T>, not template<class T> - and the latter is what your base class is expecting. But MyTrajectoryPoint<MyType> names a type, so you can use it as template parameter of your base class.
Of course, you can change declaration of BaseTrajectoryPoint to template<template<class> class T_leaftype>, but then you would have to use class template as template parameter, never a complete type.
What our friend Griwes said is correct, although if you know that every class that will inherit BaseTrajectoryPoint is a template class, you can do the following:
template<template < class > class TLeaf> // << This means: It is expected a template class as parameter
class BaseTrajectoryPoint{
};
template <class MyType>
class MyTrajectoryPoint: public BaseTrajectoryPoint<MyTrajectoryPoint> >{
private:
MyType A;
};
I have an inheritance chain of CRTP classes. The CRTP classes derive from each other, until a 'final' derived class passes itself as the CRTP parameter and finalizes the inheritance chain.
template <class W>
struct Base
{
.....
};
template <class W>
struct Derived_inheritable: public Base<W>
{
....
}
template <class W>
struct Derived2_inheritable: public Derived_inheritable<W>
{
....
}
...
What I want to do is to be able to have such 'final' end-user classes at each level of the CRTP inheritance chain, that involve no templates:
typedef Derived1_inheritable<Derived1> Derived1;
As you can guess, this typedef does not work, because it references its own type being defined. The question is how to achieve this?
The way I could think of, is:
struct Derived1: public Derived1_inheritable<Derived1>
{
//not convenient, need to redefine at least a forwarding constructor
}
As the comment in the code says, this is not a very elegant solution - I need to redefine the constructor to forward to the base constructor. Does anyone know a more elegant way?
typedef Derived1_inheritable Derived1;
That line makes no sense, the argument to the template is a type but you are trying to pass a template (incidentally the same template that you are instantiating, but besides that extra quirk the fact is that your template takes a type as argument and you are passing a non-type)
It is not really clear from the question what you are trying to achieve. You should work on stating your goal rather than your approach to solving that goal.
I want to make a "final" class for each DerivedX_inheritable that is non-template and passes itself as the W parameter.
That is exactly done in the code that you produded:
struct Derived1: public Derived1_inheritable<Derived1> {}
which is a type definition (make a "final" class). The fact that your CRTP bases require arguments that must be provided by the end user and the need of the forwarding constructor thereof is just a side effect of your design.
I think I found an elegant solution:
template <class W>
struct Base
{
.....
};
template <class W>
struct Derived_inheritable: public Base<W>
{
....
}
//solution
struct Derived2_dummy;
template <class W=derived2d_ummy>
struct Derived2_inheritable: public Derived_inheritable<W>
{
....
}
struct derived2_dummy: public: Derived_inheritable<>{};
typedef Derived2_inheritable<> Derived2;
How would I do to extend a template class, for example vector? The below code does not work. The compiler whines about 'Vector' not being a template.
template <typename T>
class Vector<T> : public std::vector<T>
{
public:
void DoSomething()
{
// ...
}
};
Your syntax is wrong; you need to use:
template <typename T>
class Vector : public std::vector<T>
That said, you should not extend the standard library containers via inheritance, if for no other reason then because they do not have virtual destructors and it is therefore inherently unsafe.
If you want to "enhance" std::vector, do so using composition (i.e., with a member variable of std::vector type) or use non-member functions to provide your additional functionality.
This has nothing to do with extending another class. The problem is your own derived class.
You define a class template like this:
template <typename T>
class Vector
{
...
and not
template <typename T>
class Vector<T>
{
...