2013-02-08 3 views
9

Edit: sto usando TDM-gcc-4.7.1-2 per WindowsCome disambiguare più typedef ereditati da basi basate su modelli?

Non sai come risolvere questo. Mi piacerebbe usarlo come una sorta di lista di tipi che mi faccia sapere che sto tentando di usare un tipo non presente nei typedef di B.

template <typename T, typename U> 
struct A { 
    typedef pair<T, U> type; 
}; 

struct B : A<int, string>, A<int, float> {}; 

B::type foo; // won't compile, ambiguous reference, as expected 
B::A<int, int>::type bar; // compiles fine?? :(

C'è un modo per farlo fallire su A<int, int> (e qualsiasi altro A 's non ereditate da B), o di un altro modo per andare su questo? Immagino che potrei usare un tuple e ricorrere in questo modo, facendo un confronto is_same su ogni elemento rispetto a qualsiasi cosa nutro il metafunction, ma questo mi è sembrato più semplice ... all'inizio: \

+0

dubito che 'B :: Un :: type' dovrebbe compilare a tutti ...'B :: A' è già ambiguo e non si riferisce al modello ma a una delle istanze da cui' B' deriva ... –

+0

@ DavidRodríguez-dribeas Sono d'accordo, non vedo perché compili. Probabilmente mi manca una regola sepolta nello standard. –

+0

Credo che la sezione sia 14.6.1-4 in bozza di C++ 11. Permette esplicitamente questo caso – jmetcalfe

risposta

6

Questo accade perché i modelli di classe hanno il loro modello di nome-iniettato; il nome inserito può essere utilizzato come modello o come tipo che fa riferimento all'istanza del modello (14.6.1p1). Il nome della classe iniettata viene quindi ereditato dalla classe derivata (10.2p5); utilizzarlo come modello è inequivocabile (è lo stesso modello ma è ereditato) quindi è permesso.

di riparare il vostro programma, provare a utilizzare is_base_of:

struct B : A<int, string>, A<int, float> { }; 
template<typename T, typename U> 
using check_A = typename std::enable_if<std::is_base_of<A<T, U>, B>::value, A<T, U>>::type; 

check_A<int, float>::type bar1; // compiles 
check_A<int, int>::type bar2; // error 
+0

Bella chiamata sul controllo di base! : D Grazie. –

2

In §11.1/5, il standard dice:

in una classe derivata, la ricerca di un nome di classe base troverà la classe nome-iniettato invece del nome della classe base nel campo di applicazione in cui è stata dichiarata. Il nome della classe iniettata potrebbe essere inferiore a accessibile rispetto al nome della classe base nell'ambito in cui è stato dichiarato .

Quindi A è un nome immesso nell'ambito di B. Si riferisce al modello A, non alla classe base (perché sarebbe ambiguo) in base al §14.1/4.

Proprio come nel campo di applicazione di A, se si dice solo A, è la classe stessa (ma è il modello in questo contesto). Stai facendo uso di questo nome iniettato, quindi il nome B::A è lo stesso di ::A. Non penso che ci sia un modo per sopprimere questo comportamento.

2

Lo standard lo consente esplicitamente, anche se è un po 'di confusione. Da 14.6.1-4 in pescaggio

Una ricerca che trova una classe nome iniettato (10.2) può provocare una ambiguità in taluni casi (ad esempio, se è presente in più di una classe base). Se tutti i nomi di classe iniettati trovati fanno riferimento a specializzazioni dello stesso modello di classe e se il nome è seguito da un elenco argomento-modello, il riferimento si riferisce al modello di classe stesso e non a una specializzazione di ciò, e non è ambiguo.

[ Example: 
template <class T> struct Base { }; 
template <class T> struct Derived: Base<int>, Base<char> { 
typename Derived::Base b; // error: ambiguous 
typename Derived::Base<double> d;// OK 
}; 
— end example ]