mercredi 20 mars 2019

CRTP traits only working with templated derived class

I have seen an idiom for using Derived type traits in the base class of a CRTP pattern that looks like this:

template<typename Derived>
struct traits;

template<typename Derived>
struct Base {
    using size_type = typename traits<Derived>::size_type;
};

template <typename T>
struct Derived1 : Base<Derived1<T>>{
    using size_type = size_t;
    void print(){ std::cout << "Derived1" << std::endl; }
};

template <typename T>
struct traits<Derived1<T>> {
    using size_type = size_t;
};

int main()
{
    using T = float;
    Derived1<T> d1;
    d1.print();
}

My understanding is that the purpose of the idiom is to delay the instantiation of the Base class's size_type. What I am confused by is the fact that this pattern only seems to work if the derived class is itself templated. For instance, if we change the code to:

template<typename Derived>
struct traits;

template<typename Derived>
struct Base {
    using size_type = typename traits<Derived>::size_type;
};

struct Derived1 : Base<Derived1>{
    using size_type = size_t;
    void print(){ std::cout << "Derived1" << std::endl; }
};

template <>
struct traits<Derived1> {
    using size_type = size_t;
};

int main()
{
    Derived1 d1;
    d1.print();
}

then we get the error

prog.cc: In instantiation of 'struct Base<Derived1>':
prog.cc:21:19:   required from here
prog.cc:18:58: error: invalid use of incomplete type 'struct traits<Derived1>'
     using size_type = typename traits<Derived>::size_type;
                                                          ^
prog.cc:14:8: note: declaration of 'struct traits<Derived1>'
 struct traits;
        ^~~~~~
prog.cc: In function 'int main()':
prog.cc:33:9: error: 'Derived1' is not a template
         Derived1<float> d1;

Could somebody give me an explanation indicating why the templated derived class compiles, but the untemplated class does not?

Aucun commentaire:

Enregistrer un commentaire