2015-04-29 22 views
10

Ho una classe che accetta un parametro di tipo template (tTRAIT). Voglio un amico un modello tipomembroalias di tTRAIT, ma non riesco a capire la sintassi. (E 'anche possibile?). Errore diC++: sintassi corretta per l'amicizia di un membro del tipo di modello del parametro del modello?

template <bool bBOOL> 
struct SFoo {}; 

struct STrait 
    { 
     template <bool bBOOL> 
     using TFoo = SFoo<bBOOL>; 
    }; 

template <typename tTRAIT> 
struct SBar 
    { 
     template <bool bBOOL> 
     friend typename tTRAIT::template TFoo<bBOOL>; 
    }; 

SBar<STrait> bar; 

di Clang (sulla linea friend) è:

error: friend type templates must use an elaborated type 

ho cercato esaurire tutte le possibili combinazioni mi viene in mente:

friend tTRAIT::TFoo; 
friend tTRAIT::template TFoo; 
friend typename tTRAIT::TFoo; 
friend typename tTRAIT::template TFoo; 
template <bool bBOOL> friend tTRAIT::TFoo; 
template <bool bBOOL> friend tTRAIT::TFoo<bBOOL>; 
template <bool bBOOL> friend tTRAIT::template TFoo; 
template <bool bBOOL> friend tTRAIT::template TFoo<bBOOL>; 
template <bool bBOOL> friend typename tTRAIT::TFoo; 
template <bool bBOOL> friend typename tTRAIT::TFoo<bBOOL>; 
template <bool bBOOL> friend typename tTRAIT::template TFoo; 
template <bool bBOOL> friend typename tTRAIT::template TFoo<bBOOL>; 

Ho anche provato ad utilizzare using, ma non sembra aiutare.

Come un brutto attacco (che funziona solo per i parametri bool), posso farlo funzionare ampliando manualmente ciascuna specializzazione.

friend typename tTRAIT::template TFoo<false>; 
friend typename tTRAIT::template TFoo<true >; 

Ma questo è schifo.

Qualcuno sa come farlo, o se questo può essere fatto?

risposta

4

Non credo sia possibile. Da standard draft N4296:

§ 14.5.4/1 [temp.friend]

Un amico di un modello di classe o di classe può essere un modello di modello di funzione o classe, una specializzazione di un modello di funzione o modello di classe o una funzione o classe non di modello.

Questo non include i modelli di alias, quindi lo standard non supporta ciò che si desidera fare. Questo è forse dovuto al seguente estratto (sottolineatura mia):

§ 14.5.7/1 [temp.alias]

Un modello-dichiarazione nella quale la dichiarazione è un alias-dichiarazione (Clausola 7) dichiara che l'identificatore a è un modello alias. Un modello alias è un nome per una famiglia di tipi.

un alias nomi dei modelli una famiglia separata di tipi, quindi, anche se ci fosse una sintassi che aveva un senso per questo, si sarebbe friending il modello alias piuttosto che il modello che viene alias.

Per esempio, GCC compila questo (Clang non sarà), ma non sarà effettivamente in grado di utilizzare l'amicizia in alcun modo ragionevole:

template <bool B> 
using MyTFoo = typename tTRAIT::template TFoo<B>; 

template <bool> friend class MyTFoo; 

Un altro esempio di come un modello di alias è non è la stessa del modello alias:

template <template <typename...> class A, template <typename...> class B> 
struct is_same_template : std::false_type{}; 

template <template <typename...> class A> 
struct is_same_template<A,A> : std::true_type{}; 

template <typename T> using myvec = std::vector<T>; 

//this fails 
static_assert(is_same_template<myvec,std::vector>::value, "wat"); 

tuo friending manuale con istanziazione esplicita funzionerà, perché il modello alias crollerà verso il basso esattamente dello stesso tipo del modello alias. Un esempio analogo:

//this passes! 
static_assert(std::is_same<myvec<int>,std::vector<int>>::value, "wat"); 
+0

Beh, questo è interessante e fastidioso, dal momento che sto usando attivamente "manualmente amico sia le specializzazioni vero e falso" con clang (3.7.0/C++ 1z) e è sicuramente un amico del tipo reale (non-alias). Forse è illegalmente bello per me? – xaxazak

+0

I compilatori non compilano diverse versioni di codice per le classi e i loro alias (giusto?), Quindi per una classe e per il suo alias, entrambi possono vedere cose private o nessuna (dato che c'è una sola versione condivisa delle loro funzioni). Non puoi separarli. – xaxazak

+0

Per la gestione manuale, funzionerà correttamente, poiché l'istanziazione del modello alias e il modello stesso saranno esattamente dello stesso tipo. Sono solo i modelli che sono distinti, le istanze non lo sono. – TartanLlama

2

Posso andare avanti con Clang 3.4.1 in std = C++ 11 modalità.

Questo compila senza errori:

modello

struct SBar 
    { 
private: 
    int j; 
public: 
     template <bool bBOOL> 
     friend struct tTRAIT::TFoo; 
     void setJ(int j) { 
      this->j = j; 
     } 
}; 

Ma ... ottengo questo avvertimento: avvertimento: dipendente nidificato nome specificatore 'tTRAIT ::' per la dichiarazione amico modello non è supportato; ignorando questa dichiarazione di amicizia [-Wunsupported-friend]: friend struct tTRAIT :: TFoo;

e posso confermare che le classi non sono SFoo amico (il motivo per private j ...)

L'unico modo ho potuto avere tutto per compilare ed eseguire è:

struct SBar 
    { 
private: 
    int j; 
public: 
     template <bool bBOOL> 
     friend struct sFoo; 
     void setJ(int j) { 
      this->j = j; 
     } 
}; 

Fine, SFoo classi sono amici, ma in qualche modo sconfigge il requisito OP (tipo di modello membro di [parametro modello]) ...

Attualmente non ho accesso ad un gcc recente, ma penso che siamo qui ai margini di come i compilatori interpretano lo standard. Ho letto il capitolo di riferimento di TartanLlama, ma non potevo assicurarmi che fosse intenzionale o meno. Forse il mio primo tentativo sarebbe stato accettato da gcc ...

+0

Grazie per averlo testato. Se vuoi puoi provare "friend tTRAIT :: TFoo " (& true version), con o senza "struct". Sembra funzionare per me su C++ 1z. – xaxazak

+0

@xaxazak: non è così. ma accetta 'friend STrait :: TFoo ;'. Sembra che il tuo 3.7 in C++ 1z sia più tollerante del mio 3.4 in C++ 11 ... –

Problemi correlati