Mixing typedef and CRTP?

Consider the following example:

#include <iostream> #include <iostream> #include <type_traits> template<typename Type, template<typename> class Crtp> class Base { public: typedef int value; // f1: OK // Expected result: casts 4.2 to Base<Type, Crtp>::value value f1() {return 4.2;} // f2: NOT OK // Expected result: casts 4.2 to Crtp<Type>::value // But f2 does not compile: no type named 'value' // in 'class Derived<double>' typename Crtp<Type>::value f2() {return 4.2;} }; template<typename Type> class Derived : public Base<Type, Derived> { public: typedef Type value; }; int main() { Derived<double> a; std::cout<<a.f1()<<std::endl; std::cout<<a.f2()<<std::endl; return 0; } 

How to solve this problem ( Derived typedef is unknown from the Base class)?

EDIT: I found a very simple trick. Can someone explain to me why the following works and the previous version does not work? Is this trick normally standard C ++ 11 or does it work because of how the compiler works (here g ++ 4.7.1)?

 #include <iostream> #include <iostream> #include <type_traits> template<typename Type, template<typename> class Crtp> class Base { public: typedef int value; value f1() {return 4.2;} template<typename T = Crtp<Type>> typename T::value f2() {return 4.2;} }; template<typename Type> class Derived : public Base<Type, Derived> { public: typedef Type value; }; int main() { Derived<double> a; std::cout<<a.f1()<<std::endl; std::cout<<a.f2()<<std::endl; return 0; } 
+4
source share
2 answers

You should use a wrapper class (here it is value_getter ), which is declared before you define Base . You can then define it before you define Derived :

 template<typename T> struct value_getter; template<typename Type, template<typename> class Crtp> class Base { public: typedef int value; value f1() {return 4.2;} // in 'class Derived<double>' typename value_getter<Crtp<Type> >::value f2() {return 4.2;} }; template<typename Type> class Derived; template<typename Type> struct value_getter<Derived<Type> > { typedef Type value; }; template<typename Type> class Derived : public Base<Type, Derived>, public value_getter<Derived<Type> > { public: }; 

It is not entirely beautiful, but at least it works.

+3
source

Your trick works because f2 no ​​longer gets an instance until it is actually used, when the Derived class is complete.

In your specific example, I can simply recommend this:

 #include <iostream> #include <iostream> #include <type_traits> template<typename Type, template<typename> class Crtp> class Base { public: typedef int value; value f1() {return 4.2;} Type f2() {return 4.2;} }; template<typename Type> class Derived : public Base<Type, Derived> { public: typedef Type value; }; int main() { Derived<double> a; std::cout<<a.f1()<<std::endl; std::cout<<a.f2()<<std::endl; return 0; } 

but your real code may have other needs that make this impractical.

+1
source

All Articles