2010-12-18 10 views
12

Chcę, aby klasa pochodna była potomkiem klasy szablonu. Ta klasa zależy od członków potomka. W skrócie chcę ten kod do kompilacji:Użycie klasy pochodnej 'typedefs w bazie

struct IBootParams 
{ 
    virtual bool GetImmediate() = 0; 
}; 

template <class T> 
struct TBootBootParams 
{ 
    typename T::TransType transferType; 

    typename T::UseAbort_ useAbort; 

    bool GetImmediate() 
    { 
     if (transferType == T::e1) 
     { 
      return useAbort.someFlag; 
     } 

     return false; 
    } 

}; 

struct BootBootParams : public TBootBootParams<BootBootParams> 
{ 
    enum SomeEnum 
    { 
     e1=0, 
     e2, 
     e3 
    }; 

    struct UseAbort 
    { 
     bool  someFlag;   

     char  someMember;    
     int   otherMember;   
    } useAbort; 

    typedef SomeEnum TransType; 
    typedef UseAbort UseAbort_; 
}; 

struct BootAltBootParams : public TBootBootParams<BootAltBootParams> 
{ 
    enum SomeEnum 
    { 
     e1=5, 
     e2, 
     e3 
    }; 

    struct UseAbort 
    { 
     bool  someFlag;   

     long long  someMember;    
     long long  otherMember;   
    } useAbort; 

    typedef SomeEnum TransType; 
    typedef UseAbort UseAbort_; 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    BootBootParams bp; 
    BootAltBootParams bpa; 

    bool f = bp.GetImmediate(); 
    f = bpa.GetImmediate(); 
} 
+0

Więc jaki jest błąd? – ybungalobill

+2

Dlaczego zadeklarowałeś IBootParams? –

Odpowiedz

10

Nie możesz tego zrobić w ten sposób. Gdy kompilator tworzy instancję TBootBootParams<BootBootParams>, nie odczytał jeszcze kompletnie definicji BootBootParams, więc nie można uzyskać dostępu do jej członków z poziomu definicji TBootBootParams (funkcje składowe TBootBootParams są wyjątkiem, ponieważ są tworzone później).

Typowym rozwiązaniem jest mieć klasę cech:

template<class T> struct TBootBootParams_traits; 

template <class T> 
struct TBootBootParams 
{ 
    typename TBootBootParams_traits<T>::TransType transferType; 

    typename TBootBootParams_traits<T>::UseAbort_ useAbort; 

    bool GetImmediate() 
    { 
     if (transferType == TBootBootParams_traits<T>::e1) 
     { 
      return useAbort.someFlag; 
     } 

     return false; 
    } 

}; 

struct BootBootParams; 
template<> struct TBootBootParams_traits<BootBootParams> 
{ 
    enum SomeEnum 
    { 
     e1=5, 
     e2, 
     e3 
    }; 

    struct UseAbort 
    { 
     bool  someFlag;   

     long long  someMember;    
     long long  otherMember;   
    }; 

    typedef SomeEnum TransType; 
    typedef UseAbort UseAbort_; 
}; 

struct BootBootParams : 
    public TBootBootParams<BootBootParams>, 
    public TBootBootParams_traits<BootBootParams> 
{ 
    UseAbort_ useAbort; 
}; 
+0

To jest lepszy hack niż mój, myślę. Trochę czystszy. – Omnifarious

+0

Wygląda świetnie. Po prostu nie rozumiem, dlaczego deklaracja 'template <> struct TBootBootParams_traits' nie ma żadnych parametrów typu w' <> 'podczas gdy deklaracja do przodu działa. –

+1

@Sergey: ponieważ jest to specjalizacja. @All + @Omnifarious: To kanoniczny sposób przekazywania niektórych parametrów do jakiegoś szablonu. Na przykład. STL używa go do iteratorów (iterator_traits). – ybungalobill

4

Nie ma mowy, to może pracować, że nie jest trochę hack. Więc tutaj jest moja próba odrobiną hack:

struct IBootParams 
{ 
    virtual bool GetImmediate() = 0; 
}; 

template <class T> 
struct TBootBootParams : public IBootParams 
{ 
    typename T::TransType transferType; 

    typename T::UseAbort_ useAbort; 

    virtual bool GetImmediate() 
    { 
     if (transferType == T::e1) 
     { 
      return useAbort.someFlag; 
     } 

     return false; 
    } 

}; 

struct BootBootParams_types 
{ 
    enum SomeEnum 
    { 
     e1=0, 
     e2, 
     e3 
    }; 

    struct UseAbort 
    { 
     bool  someFlag; 

     char  someMember; 
     int   otherMember; 
    } useAbort; 

    typedef SomeEnum TransType; 
    typedef UseAbort UseAbort_; 
}; 

struct BootBootParams : public BootBootParams_types, 
         public TBootBootParams<BootBootParams_types> 
{ 
}; 

struct BootAltBootParams_types 
{ 
    enum SomeEnum 
    { 
     e1=5, 
     e2, 
     e3 
    }; 

    struct UseAbort 
    { 
     bool  someFlag; 

     long long  someMember; 
     long long  otherMember; 
    } useAbort; 

    typedef SomeEnum TransType; 
    typedef UseAbort UseAbort_; 
}; 

struct BootAltBootParams : public BootAltBootParams_types, 
          public TBootBootParams<BootAltBootParams_types> 
{ 
}; 

int main(int argc, const char * argv[]) 
{ 
    BootBootParams bp; 
    BootAltBootParams bpa; 

    bool f = bp.GetImmediate(); 
    f = bpa.GetImmediate(); 
} 
+1

+1, ponieważ byłeś blisko :) – ybungalobill

+1

Dzięki. Ciekawy! – Romeno

0

Na takie podejście do pracy, trzeba to obiekt klasy szablonu jako członek klasy nadrzędnej.

2

robi tego, czego chcesz? It compiles.

struct IBootParams 
{ 
    virtual bool GetImmediate() = 0; 
}; 

template <class T> 
struct TBootBootParams 
{ 
    bool GetImmediate() 
    { 
     if (static_cast<T*>(this)->transferType == T::e1) 
     { 
      return static_cast<T*>(this)->useAbort.someFlag; 
     } 

     return false; 
    } 

}; 

struct BootBootParams : public TBootBootParams<BootBootParams> 
{ 
    enum SomeEnum 
    { 
     e1=0, 
     e2, 
     e3 
    } transferType; 

    struct UseAbort 
    { 
     bool  someFlag;   

     char  someMember;    
     int   otherMember;   
    } useAbort; 
}; 

struct BootAltBootParams : public TBootBootParams<BootAltBootParams> 
{ 
    enum SomeEnum 
    { 
     e1=5, 
     e2, 
     e3 
    } transferType; 

    struct UseAbort 
    { 
     bool  someFlag;   

     long long  someMember;    
     long long  otherMember;   
    } useAbort; 
}; 

int main(void) 
{ 
    BootBootParams bp; 
    BootAltBootParams bpa; 

    bool f = bp.GetImmediate(); 
    f = bpa.GetImmediate(); 
} 
+0

Wow. Jestem pod wrażeniem, że kompiluje. Czy ma się skompilować? To, że tak naprawdę działa, nie oznacza, że ​​powinno. :-) – Omnifarious

+0

BTW, to także kompiluje na gcc 4.5. – Omnifarious

+0

@Omnifarious: Tak, to powinno się skompilować, to proste CRTP. Pozbyłem się podstawowych elementów klasy, które powodowały problem ... ponieważ ich typ danych jest określany przez typ pochodny, mogą one być zadeklarowane w typie pochodnym, a klasa podstawowa może uzyskać do nich dostęp bez problemu, wykorzystując parametr szablonu . –

1

Próbowałem trochę zmienić rozwiązanie ybungalobill licząc moje własne potrzeby. I to, co mam

template<class T> 
struct TBootBootParams_traits; 

template <class T> 
struct TBootBootParams 
{ 
    typedef TBootBootParams_traits<T> Traits; 

    typename Traits::TransType transferType; 
    typename Traits::UseAbort_ useAbort; 

    bool GetImmediate() 
    { 
     if (transferType == TBootBootParams_traits<T>::e1) 
     { 
      return useAbort.someFlag; 
     } 

     return false; 
    } 
}; 

struct BootBootParams; 
struct BootAltBootParams; 

template<> 
struct TBootBootParams_traits<BootBootParams> 
{ 
    enum SomeEnum 
    { 
     e1=5, 
     e2, 
     e3 
    }; 

    struct UseAbort 
    { 
     bool  someFlag;   

     long long  someMember;    
     long long  otherMember;   
    }; 

    typedef SomeEnum TransType; 
    typedef UseAbort UseAbort_; 
}; 

template<> 
struct TBootBootParams_traits<BootAltBootParams> 
{ 
    enum SomeEnum 
    { 
     e1=5, 
     e2, 
     e3 
    }; 

    struct UseAbort 
    { 
     bool  someFlag;   

     int someMember;    
     float otherMember;   
    }; 

    typedef SomeEnum TransType; 
    typedef UseAbort UseAbort_; 
}; 

struct BootBootParams : 
    public TBootBootParams<BootBootParams> 
{ 

}; 

struct BootAltBootParams : 
    public TBootBootParams<BootAltBootParams> 
{ 

}; 

int main(void) 
{ 
    BootBootParams bp; 
    BootAltBootParams bpa; 

    bool f = bp.GetImmediate(); 
    f = bpa.GetImmediate(); 
} 

Podsumowując .. I użyć klasy szablonu jako must-have opcją innej klasy dla tej klasy umieszczając tam wszystkie dane typu. Właśnie tego potrzebowałem. Jeszcze raz dziękuję za opcję!

Powiązane problemy