c++ - Why can't my Curiously Recurring Template Pattern (CRTP) refer to the derived class's typedefs? -


this question has answer here:

when using curiously recurring template pattern, unable refer typedefs belonging derived class only if attempt reference them base class; gcc complains no type named 'mytype' in class derived<...>. seems inconsistent otherwise possible using typedefs, templates, , curiously recurring relationships.

consider:

/* crtp.cpp */  #include <iostream> using namespace std;  // case 1. simple.  class base { public:     typedef int a_t;      a_t foo; };  class derived : public base {     a_t bar; };  // case 2. template.  template<typename t> class tbase { public:     typedef t b_t;     t foo; };  template <typename t> class tderived : public tbase<t> {     typename tbase<t>::b_t bar; };  // case 3. curiously recurring.  template <typename t, typename d> class tcuriousbase { public:     typedef t c_t;     c_t foo; };  template <typename t> class tcuriousderived : public tcuriousbase<t,tcuriousderived<t> > {     typename tcuriousbase<t,tcuriousderived<t> >::c_t bar; };  // case 4. curiously recurring member reference.  template <typename t, typename d> class tcuriousmemberbase { public:     t foo;      t get() {         return static_cast<d*>(this)->bar;     } };  template <typename t> class tcuriousmemberderived : public tcuriousmemberbase<t, tcuriousmemberderived<t> > { public:     t bar;      tcuriousmemberderived(t val) : bar(val) {} };  // case 5. curiously recurring typedef reference.  template <typename t, typename d> class tcurioustypebase { public:     typedef t d_t;     d_t foo;     typename d::c_t baz; };  template <typename t> class tcurioustypederived : public tcurioustypebase<t, tcurioustypederived<t> > { public:     typedef t c_t;     typename tcurioustypebase<t,tcurioustypederived<t> >::d_t bar; };  // entry point  int main(int argc, char **argv) {     derived::a_t 1 = 1;     tderived<double>::b_t 2 = 2;     tcuriousderived<double>::c_t 3 = 3;     double 4 = tcuriousmemberderived<double>(4).get();     tcurioustypebase<double, tcuriousderived<double> >::d_t 5 = 5;     // tcurioustypederived<double>::d_t 6 = 6; /* fails */      cout << 1   << endl;     cout << 2   << endl;      cout << 3 << endl;     cout << 4  << endl;     cout << 5  << endl;     // cout << 6 << endl; } 

from (1), see typedefs indeed inherited base derived; typedef declared in base class can accessed through derived class.

from (2), see still true if both classes templates.

from (3), see typedef inheritance can still exist in presence of curiously recurring template relationship; refer base's typedef via derived class in our declaration of three.

from (4), see member variables of derived class may readily accessed base class.

from (5), see can access typedef defined on template parameter (this works when declare five using types not related inheritance).

as make template parameter derived class in (6), however, typedef becomes inaccessible, though seemingly well-defined member variable in derived class.

why this?

this "circular dependecies", or "incomplete-type" alter-ego.

template "meta-programming" "programming types", requires level of sematics known instantiate types.

consider analogy:

class a; //forwarded  class b {    a* pa; //good: know how wide pointer is, no matter if don't know yet a.    a; // bad: don't know how space requires };  class {   float m; }; // know, it's late 

this can solved placing before b, if is

class {    b m; }; 

thhere no other solution pointers, since recursion infinite. (a should contain itself, not refer copy)

now, with same analogy, let's program "types":

template<class d> class {    typedef typename d::inner_type my_type; //required d known when a<d> instantiated...    my_type m; // ... otherwise cannot know how wide a<d> be. }; 

this declaration not bad,until start define d ...

class d: //here know d exist     public a<d> //but size depende on d definition... {   ....   typedef long double; inner_type   .... }; // ....we know starting here 

so, basically, don't know (yet) how wide @ time need use create d.

one way break "circularity" use "traits classes" outside of crt loop:

struct traits {    typedef long double inner_type;    .... };  template<class d, class traits> class {   // easy: traits not depend on   typedef typename traits::inner_type my_type;   .... };  template<class traits> class d: public a<d, traits> {   typedef typename traits::inner_type inner_type; }; 

an can declare

typedef d<traits> d_inst; 

in other words, coherence between a::my_type , d::inner_type ensured traits::inner_type, definition independent.


Comments

Popular posts from this blog

node.js - Bad Request - node js ajax post -

Why does Ruby on Rails generate add a blank line to the end of a file? -

keyboard - Smiles and long press feature in Android -