CRTP intermediate class that needs to also be made final - c++

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;

Related

CRTP - "abstract" method in static interface

I am trying to work out some way to enforce contract between base CRTP class and the derived one. When using dynamic polymprhpism, one can simply do:
struct foo{
virtual bar() = 0;
};
And the compiler will make sure that the method bar is implemented in deriving class, otherwise it will give (more or less) meaningful error message. Now the best I could get with CRTP to is something like this:
template<class Derived>
struct base {
void stuff(){
static_cast<Derived &>(*this).baz();
}
};
Which will somehow enforce implementation of baz in derived class but is not really readable and clear what the contract between base and derived class is. So my question is, is there a way to do this better? I am aware of C++20 Concepts and that they would be perfect solution for this case, but I am looking for C++11/C++14 solution to make it as clean as possible.
Since the derived class is always incomplete when a base is defined one solution I use is to delay "concept check" instantiation using a defaulted template parameter:
template<class T>
using has_baz = decltype(std::declval<T&>().baz());
template<class Derived>
struct base{
template<class T = Derived, has_baz<T>* =nullptr>
void stuff(){/*...*/}
};
Notice, c++20 concepts will not solve this special issue and the delaying of the concept check will still be necessary. The advantage is that the compilation error will be clearer.
Demo

Is typedeffing templated base class to simplify the code a good practice?

I caught myself "inventing" this simple construct lately when working with many templated classes and deriving from them. I am not sure if it is common practice, or am I tying a rope around my neck.
template <typename T> class Base {};
template <typename T> class Derived : public Base<T>{
typedef Base<T> Base;
};
I found it especially useful if the Base class has its own typedefs for some types. E.g:
template <typename T> class Base {
typedef T Scalar;
typedef Matrix<Scalar> Matrix;
};
Then it's easy to "import" types into the Derived. It saves re-typing the template signature. E.g:
template <typename T> class Derived : public Base<T>{
typename Base<T>::Matrix yuck_yuck(); //that's what I am trying to simplify
typedef typename Base<T> Base;
typedef typename Base::Matrix Matrix;
Matrix much_fun(); //looks way better
};
Also on of the big advantages is that, when you want to add another template parameter to the Base class. You don't have to go over a bunch of functions to change, just update the typedef. much_fun will have no problem if Base will be changed to Base<T,U> while yuck_yuck will need to have updated signatures (not sure if template parameter is formally included with the signature, so pardon me if I am making a formal error here, but I think it is).
Is this a good practice or am I playing with a gun next to my vital parts? It looks like it makes code more readable, and simplifies it, but maybe I am missing something that can backfire.
EDIT2: I got the working example. The Base class must be within its namespace or there will be conflicts with the same names within a scope, as the commenters pointed out. Below is the minimal example that embodies my real question.
namespace Fun {
template <typename T> class Base {
public:
typedef T Scalar;
};
}
template <typename T>
class Derived : public Fun::Base<T>{
public:
typedef typename Fun::Base<T> Base;
typedef typename Base::Scalar Scalar;
typename Fun::Base<T>::Scalar yuck_yuck();
Scalar much_fun();
};
#include <iostream>
using namespace std;
int main() {
Derived<double> d;
return 0;
}
With lots of stuff the code gets really bloated with typenames, and template parameters. But I already run into a trouble making up the example, by not placing Base in its own namespace. I wonder if there are any other caveats, that are actually killers to the idea.
I believe this is ill-formed, due to rule 2 of C++11 3.3.7/1
A name N used in a class S shall refer to the same declaration in its context and when re-evaluated in the completed scope of S.
meaning that you can't use the name Base to refer to both the template and the typedef within the class scope. Certainly, my compiler won't accept it:
error: declaration of ‘typedef struct Base<T> Derived<T>::Base’ [-fpermissive]
error: changes meaning of ‘Base’ from ‘struct Base<T>’ [-fpermissive]
(NOTE: this refers to the simplified example originally posted, and doesn't cover the updated question where the base class name is in a different scope.)
I actually consider it a helpful (and good) practice if the typedef is not exposed public or protected:
// No template, not Base, to avoid that discussion
class Derive : public SomeBaseClass
{
private:
typedef SomeBaseClass Base;
public:
typedef Base::T T;
T f();
};
class MoreDerived : public Derived
{
// Base is not accessible
};

C++ Using a template class pointer as a template parameter without giving it a parameter

The title is a little confusing, so hopefully I can clear that up.
I have a simple class that uses a template:
template <class T>
class Value
{
};
And another class that extends unordered_set:
template<class T>
class Collection : public std::unordered_set<T>
{
};
These classes both have some other code, but I don't think any of it is relevant to my question.
In a particular implementation of the Collection class, I want it to be able to take pointers to any Value, regardless of the template parameter that was used when creating it. In other words, I want to be able to have something semantically similar like this:
class ValueCollection : public Collection<Value*>
{
};
ValueCollection *vc = new ValueCollection();
vc.insert(new Value<std::string>("hello"));
vc.insert(new Value<int>(5));
Of course, that doesn't work. How I would obtain similar functionality?
Just give you Value class template a common base class, making sure that it has a virtual destructor and using this to add your instantiated values:
struct ValueBase {
virtual ~ValueBase() {}
};
template <typename T>
struct Value
: ValueBase {
};
BTW, you are generally better off not inheriting the STL containers: They are not designed for inheritance you are most likely to cause subtle problems than benefitting from the little amount of saved work.

How to declare data members that are objects of any type in a class

In this piece I'm trying to declare in Class B a list that can hold objects of Class A of any type, such as A<int>, A<double>, A<float>. I intend to add A objects to the list during runtime:
#include <list>
template <class T> class A {};
class B {
template<class T> std::list<A<T>*> objects;
};
It seems like making a list like this should work but compiling it gives an error:
Line 6: error: data member 'objects' cannot be a member template
compilation terminated due to -Wfatal-errors.
Can somebody explain why this doesn't work and how I can fix it?
That's just not how C++ works. If you want to group different objects together, they need to have at least some relation. Being instantiations of the same class template doesn't imply that they are related, they're completely distinct types. If you want a list of A<T>*s, better make a list of base-class pointers and forward operations through virtual functions:
class A_base{
public:
virtual void foo() = 0;
virtual ~A_base() { }
};
template<class T>
class A : public A_base{
public:
void foo(){
// ...
}
};
class B{
std::list<A_base*> objects;
};
Member variables aren't allowed to be templates. Only member functions can be templates. You'll have to templatize the enclosing class B instead:
template <class T>
class B {
std::list<A<T>*> objects;
};
Unfortunately you cannot have template variables. Only option to declare a member data is to make the class template:
template<class T>
class B {
std::list<A<T>*> objects;
};
Depending on what you're doing, type erasure might be an option. On the Tension Between Object-Oriented and Generic Programming in C++ is my favorite write-up on the subject.
In a nutshell, you convert the static dispatch enabled by the templates into dynamic dispatch through a custom inheritance tree you setup on the fly. Instead of storing A<T>, you create a new type that has the common interface you desire, and using some template/inhertiance voodoo this new type stores an A<T> without actually exposing the T. So A<int> and A<double> and A<A<std::list<A<int> > > > and some_type_that_looks_like_A_but_really_isnt all reduce down to a single type.
But you have to have a common interface, independant of that parameter. If you can't, things get more difficult.
Boost.Any is a good example, as is std::shared_ptr [which uses type erasure to remember how to delete the pointer passed to it even in the face of non-polymorphic inheritance].
Make B class template just like you've made A a class template:
template<class T>
class B {
std::list<A<T>*> objects;
};

Inherit from specialized templated base class and call the right method

I.e. I got 2 specialized types of:
template <class Type, class Base> struct Instruction {};
to compile-time-select the appropriate type from within a type list.
like:
template <class Base> struct Instruction<Int2Type<Add_Type>, Base >
{
void add() {}
};
template <class Base> struct Instruction<Int2Type<Mul_Type>, Base > :
Instruction<Int2Type<Add_Type>, Base >
{
void mul()
{
add(); ???? <== not working (not resolved)
}
};
What's the solution for this?
Thank you
Martin
add() doesn't appear to depend on any template parameters (it's not a "dependent name"), so the compiler doesn't search for it in the templated base class.
One way to make it clear to the compiler that add() is supposed to be a member function/dependent name, is to explicitly specify this-> when you use the function:
void mul()
{
this->add();
}
this implicitly depends on the template parameters, which makes add a dependent name that is looked up in the templated base class.
See also this entry of the C++ FAQ lite, and the next/previous ones.
Got it using a "using base method" clause like:
using base::add;
One disadvantage is to declare that using clauses for all base methods. On advantage is the implicit distinctive nature of it selecting only that methods, which are allowed to resolve (use).
Sorry for that question of a dude which forgets his head somewhere.