Home > Mobile >  Is there any way to make this CRTP work with inheritance?
Is there any way to make this CRTP work with inheritance?

Time:09-22

Pardon the very vague question but I am struggling with even finding the proper words to describe what I'm trying to do. Basically, when I write a class I like having:

class A
{
public:
    using uptr = std::unique_ptr<A>;
    using sptr = std::shared_ptr<A>;
    using wptr = std::weak_ptr<A>;

};

So I can use A::uptr and such.

Now I am starting to have a lot of classes with this mechanism and I was wondering if it was posssible to generalize it, somehow like this:

template <typename T>
class Ptrs
{
public:
    using uptr = std::unique_ptr<T>;
    using sptr = std::shared_ptr<T>;
    using wptr = std::weak_ptr<T>;
};

class A : public Ptrs<A>
{
};

This seems to work properly but as soon as I introduce inheritance, it breaks. For example:

class B : public A
{
};

B::uptr b; // this is a unique_ptr<A>

class B : public Ptrs<B>, public A // does not compile
{
};

So I was wondering if there was any way to do this. I am using C 20, I am just not very familiar with templates / concepts / SFINAE and such. I am also not sure if this is even a good idea, I just thought it would be nice to have a way to do this.

CodePudding user response:

When you derive B from both Ptrs<B> and A you're introducing two sets of identical type aliases. Therefore, the compiler is not able to figure out which one you want.

The use of the CRTP cannot help you here. However, it's opposite pattern, mixins, may help you. Mixins are small classes that are intended to add common functionality to (unrelated) classes. Instead of deriving A and B from Ptrs, you derive Ptrs from A or B. Here is an example:

#include <memory>

template <typename T>
class Ptrs : public T
{
public:
   using uptr = std::unique_ptr<T>;
   using sptr = std::shared_ptr<T>;
   using wptr = std::weak_ptr<T>;
};

class A
{
};

class B : public A
{
};

int main()
{
    Ptrs<A>::uptr a;
    Ptrs<B>::uptr b;
}

I don't know if this suites your need but this is the closest I can find.

CodePudding user response:

Yes you can do this if you turn things around on their head a bit.

template <class Base, class Derived> 
struct Ptrs : public Base {
  using uptr = std::unique_ptr<Derived>;
  // etc
};

 struct None {};

 class A : public Ptrs<None, A> {};

 class B : public Ptrs<A, B> {};

This is not pretty because the inheritance structure is not obvious, but it works for the most part (warning: specifically the above code is untested).

  • Related