2013-08-22 7 views
6

Sto provando a utilizzare una forma semplice di CRTP (Pattern modello ricorrente in modo curioso) poiché ho diverse classi, ognuna con diverse classi correlate e voglio un mezzo di associazione insieme (ad es. ho classi come Widget, Doobry e Whatsit, con classi correlate WidgetHandle, DoobryHandle e WhatsitHandle).Errori di compilazione per un caso CRTP semplice con tipi dipendenti

Ogni classe che utilizzo per ereditare da Base aggiunge un typedef value_type in modo che la classe base possa riferirsi ad esso come typename TWrapper::value_type.

struct WidgetHandle {}; 

template <typename TWrapper> 
class Base 
{ 
public: 
    Base(typename TWrapper::value_type value_) 
     : value(value_) {} 

    typename TWrapper::value_type value; 
}; 

class Widget : public Base<Widget> 
{ 
public: 
    typedef WidgetHandle value_type; 

    Widget(WidgetHandle value_) : Base<Widget>(value_) {} 
}; 

int main(int argc, char* argv[]) 
{ 

    Widget i(WidgetHandle()); 
    return 0; 
} 

Comunque, sto ricevendo errori di compilazione:

scratch1.cpp(10): error C2039: 'value_type' : is not a member of 'Widget' 
scratch1.cpp(16) : see declaration of 'Widget' 
scratch1.cpp : see reference to class template instantiation 'Base<TWrapper>' being compiled 
1>   with 
1>   [ 
1>    TWrapper=Widget 
1>   ] 
scratch1.cpp(10): error C2039: 'value_type' : is not a member of 'Widget' 

Questo è con VS2010, se sto ricevendo errori simili con clangore. Cosa mi manca qui?

+0

'Widget' è un tipo incompleto quando lo si passa come parametro a' Base'. – jrok

+0

Non vedo 'value_type' definito da nessuna parte, in effetti. – lapk

+0

@PetrBudnik È, all'inizio del corpo di 'Widget'. – jrok

risposta

1

Modificare la definizione di Base per prendere l'ha digitare come secondo parametro per evitare la dipendenza circolare.

struct WidgetHandle {}; 

template <typename TWrapper, typename HandleType> 
class Base 
{ 
public: 
    typedef HandleType value_type; 

    Base(HandleType value_) 
     : value(value_) {} 

    HandleType value; 
}; 

class Widget : public Base<Widget, WidgetHandle> 
{ 
public: 
    Widget(WidgetHandle value_) : Base(value_) {} 
}; 

int main(int argc, char* argv[]) 
{ 

    Widget i(WidgetHandle()); 
    return 0; 
} 

È anche possibile utilizzare una classe di caratteri per ottenere il tipo WidgeHandle per Widget.

struct WidgetHandle {}; 
class Widget; 

template<class T> 
struct Handle 
{ 
}; 

template<> 
struct Handle<Widget> 
{ 
    typedef WidgetHandle type; 
}; 

template <typename TWrapper, typename HandleType = Handle<TWrapper>::type> 
class Base 
{ 
public: 
    typedef HandleType value_type; 

    Base(HandleType value_) 
     : value(value_) {} 

    HandleType value; 
}; 

class Widget : public Base<Widget> 
{ 
public: 
    Widget(WidgetHandle value_) : Base(value_) {} 
}; 

int main(int argc, char* argv[]) 
{ 

    Widget i(WidgetHandle()); 
    return 0; 
} 
+0

So che posso aggiungere altri tipi alla definizione del modello, ma è una sfortuna richiedere questo se TWrapper ha un modo per specificare il tipo che è associato a –

+0

Usa il parametro del modello predefinito per ottenere il tipo di handle dalla classe dei caratteri - almeno il codice client apparirà lo stesso. – paxos1977

+0

Questo è il trucco. Nel mio caso ho diversi tipi correlati per classe, quindi legarli insieme alla classe Tratti di handle significa che possono essere tutti dichiarati in uno. –

1

Non è possibile avere dipendenze circolari: Base ha bisogno del Widget value_type che è sconosciuto nell'istanza base.

possibile soluzione potrebbe essere: Passare il value_type come un parametro di template di base, utilizzare un modello Tratti in più, ...

Esempio:

template <typename W> 
struct WidgetTraits {}; 

template <typename W> 
class Base 
{ 
    public: 
    typedef typename WidgetTraits<W>::value_type value_type; 
}; 

class Widget; 

template<> 
struct WidgetTraits<Widget> 
{ 
    typedef WidgetHandle value_type; 
}; 

class Widget : public Base<Widget> 
{ 
}; 

Altro (leggermente diverso) Esempio :

+0

Questo è vero in generale, ma CRTP usa questa tecnica estensivamente no? http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern –

+0

ok, il modello dei tratti sembra che potrebbe essere migliore - come sarebbe? –

+0

La soluzione dei tratti è più complicata ... sceglierei il parametro del modello aggiuntivo. – Walter

Problemi correlati