BadProgrammer99
BadProgrammer99

Reputation: 847

Use the template parameter type of derived as return type for function (CRTP)?

I've recreated the problem I'm having in the code below:

template<typename T>
class A{
    using type = T::type;
    type someFunction(/*some parameters*/){/*code for the function*/}
    //other stuff
};

template<typename T>
class B : public A<B<T>>{
    typedef T type;
    //other stuff
};

The problem is that I need to have A have a function with a return type of T::type, but because B isn't completely declared at the time when A is compiled, I get the error invalid use of incomplete type ‘class B<int>’ when I try to compile it (where int could be replaced with any other type). Is there any way to get this to work?

Upvotes: 2

Views: 97

Answers (2)

R Sahu
R Sahu

Reputation: 206737

Is there any way to get this to work?

You can use a traits class to derive the type instead of using:

using type = T::type;

Example:

// Declare TypeSelector
template <typename T> struct TypeSelector;

template <typename T>
class A
{
    using type = typename TypeSelector<T>::type;
    type someFunction(/*some parameters*/){ return type {}; }
};

// Declare B.
template <typename T> class B;

// Define TypeSelector for <B<T>> first before defining B<T>
template <typename T> struct TypeSelector<B<T>>
{
    using type = T;
};

template<typename T>
class B : public A<B<T>>{
    using type = typename TypeSelector<T>::type;
    //other stuff
};

int main()
{
   // Compiles fine.
   B<int> a;
}

Upvotes: 1

Jodocus
Jodocus

Reputation: 7601

You can achieve it if you move the definition of B<T>::type to an external traits-class:

template <typename T>
struct Traits { /* maybe some default values */ };

template<typename T>
class A{
    using type = typename Traits<T>::type;
    type someFunction(/*some parameters*/){/*code for the function*/}
    //other stuff
};

template<typename T>
class B : public A<B<T>>{
    using type = typename Traits<B<T>>::type;
};

template <typename T>
struct Traits<B<T>> {
    using type = T;
};

Upvotes: 3

Related Questions