3

I'm experimenting with some code using a variadic CRTP to create mixins. I'd like the mixins to be templated on a type of the user's choice. And I've basically tried this:

template <class Base>
class Feature1 {
public:
    // why doesn't this work?!
    // using value_type = typename Base::value_type;
public:
    void extraMethod1() {
        auto base = static_cast<Base&>(*this);
        base.basicMethod();
    }
};

template <class T, template <typename> class ... Skills>
class X : public Skills<X<T, Skills...>>... {
public:
    using value_type = T;
public:
    void basicMethod() {
    }
};

using X1 = X<int, Feature1>;

So my question is if Base::basicMethod is accessible, why do I get an error with Base::value_type?

The error is:

X.cpp:6:37: error: no type named 'value_type' in 'X<int, Feature1>'
                using value_type = typename Base::value_type;
                                   ~~~~~~~~~~~~~~~^~~~~~~~~~
X.cpp:15:19: note: in instantiation of template class 'Feature1<X<int, Feature1> >' requested here
        class X : public Skills<X<T, Skills...>>... {

Both clang and g++ give similar errors, version of c++ is either 14 or 17 (since this is just an experiment).

Evan Teran
  • 87,561
  • 32
  • 179
  • 238
  • For the life of me I can't remember the reason of the error, but I do remember that you need to qualify the base class member when templates are involved: `Skills>::basicMethod()`. You can add a `using` directive to your class to bring the member into the local scope. – Cris Luengo Jul 12 '18 at 22:55
  • See here : https://stackoverflow.com/questions/6006614/c-static-polymorphism-crtp-and-using-typedefs-from-derived-classes – David Jul 12 '18 at 23:02

1 Answers1

2

With CRTP, Base class is still incomplete inside Feature1 definition.

So you cannot use alias defined inside it.

As workaround you may create traits.

template <typename T>
struct MyTrait;

template <class Base>
class Feature1 {
public:
    using value_type = typename MyTrait<Base>::type;
public:
    void extraMethod1() {
        auto base = static_cast<Base&>(*this);
        base.basicMethod();
    }
};


template <class T, template <typename> class ... Skills>
class X;

template <class T, template <typename> class ... Skills>
struct MyTrait<X<T, Skills>>
{
    using type = T;
};

template <class T, template <typename> class ... Skills>
class X : public Skills<X<T, Skills...>>... {
public:
    using value_type = typename MyTrait<X>::type;
public:
    void basicMethod() {}
};
Jarod42
  • 203,559
  • 14
  • 181
  • 302