Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CRTP + Traits class : "no type named..."

I try to implement a CRTP with templated class and I have an error with the following example code :

#include <iostream>

template<class T> class Traits
{
    public:
        typedef typename T::type type; // <- Error
                                       // : "no type named 'type' in 'class MyClass<double, 3u, 3u>'
        static const unsigned int m_const = T::m_const;
        static const unsigned int n_const = T::n_const;
        static const unsigned int size_const = T::m_const*T::n_const;
};

template<class T0> class Crtp
{
    public:
        typedef typename Traits<T0>::type crtp_type;
        static const unsigned int size = Traits<T0>::size_const; // <- This is OK
};

template<typename TYPE, unsigned int M, unsigned int N>
class MyClass : public Crtp< MyClass<TYPE, M, N> >
{
    public:
        typedef TYPE type;
        static const unsigned int m_const = M;
        static const unsigned int n_const = N;
};

int main()
{
    MyClass<double, 3, 3> x;
    std::cout<<x.size<<std::endl;
    return 0;
}

I do not understand what causes this problem nor how to fix it.

In fact my goal is that the CRTP class have to know the template arguments of the derived class WITHOUT passing them as template argument of the CRTP class.

Do you have any ideas how to implement this?

EDIT (relating to the first first) : My CRTP class has to be able to handle derived classes with different number of template parameters

like image 763
Vincent Avatar asked Aug 03 '12 12:08

Vincent


1 Answers

The problem is that MyClass is incomplete in its own base class list, where you instantiate Crtp<MyClass>. But instantiating Crtp<MyClass<...>> requires instantiating Traits<MyClass<...>> which then requires instantiating MyClass<...>::type which is impossible because it's incomplete. You have a circular dependency.

In fact my goal is that the CRTP class have to know the template arguments of the derived class

That can be done using a partial specialzation and a template-template-parameter, like so:

#include <iostream>

template<typename T> class Crtp;

template<template<typename, unsigned, unsigned> class T, typename U, unsigned M, unsigned N>
class Crtp< T<U, M, N> >
{
    public:
        typedef U crtp_type;
        static const unsigned int size = M * N;
};

template<typename TYPE, unsigned int M, unsigned int N>
class MyClass : public Crtp< MyClass<TYPE, M, N> >
{
};

int main()
{
    MyClass<double, 3, 3> x;
    std::cout<<x.size<<std::endl;
    return 0;
}
like image 165
Jonathan Wakely Avatar answered Oct 15 '22 11:10

Jonathan Wakely