2015-02-03 8 views
5

ho due operatori di modelli in classe:Quali sono le regole per la scelta tra un metodo di template variadic e un metodo di template usuale?

template<class T> 
    size_t operator()(const T& t) const { 
     static_assert(boost::is_pod<T>(), "Not a POD type"); 
     return sizeof t; 
    } 

    template<typename... T> 
    size_t operator()(const boost::variant<T...>& t) const 
    { 
     return boost::apply_visitor(boost::bind(*this, _1), t); 
    } 

mi passa boost::variant<some, pod, types, here> come argomento di questi operatori. GCC 4.8 e llvm 6.0 compilano il codice fine, scegliendo l'operatore parametrizzato boost::variant. gcc 4.7 sceglie l'operatore parametrizzato const T& t e quindi non riesce a compilare a causa dell'asserzione statica.

Quindi, ho una domanda, quali sono le regole per la scelta tra queste due? Penso che gcc 4.7 debba avere un bug, ma non ho alcuna prova.

risposta

0

In generale il compilatore tratta tutte le istanze del modello dedotte come potenziali sovraccarichi, selezionando la "funzione migliore possibile" (§ 13.3.3).

In effetti ciò significa che GCC 4.7 ha un bug quindi.

See §14.8.3: risoluzione di sovraccarico

descrive che tutte le istanze del modello si uniranno nel set di candidati come qualsiasi non-template dichiarato sovraccarico:

Un modello funzione può essere sovraccaricato sia da (non modello) funzioni del suo nome o di altri modelli di funzione con lo stesso nome. Quando una chiamata a tale nome è scritto (in modo esplicito o implicito utilizzando la notazione dell'operatore), modello argomento deduzione (14.8.2) e il controllo di qualsiasi modello esplicito argomenti (14.3) vengono eseguite per ogni modello di funzione per trovare il modello I valori degli argomenti (eventualmente) che possono essere utilizzati con tale modello di funzione su creano un'istanza di una specializzazione del modello di funzione che può essere richiamata con gli argomenti di chiamata . Per ogni modello di funzione, se la verifica dell'argomento e il controllo hanno esito positivo, gli argomenti del modello (dedotti e/o espliciti) vengono utilizzati per sintetizzare la dichiarazione di una specializzazione del modello di funzione singola che viene aggiunto alle funzioni candidate impostate per essere utilizzato in sovraccarico risoluzione. Se, per un dato modello di funzione, la deduzione dell'argomento fallisce, non viene aggiunta alcuna funzione all'insieme delle funzioni candidate per quel modello. Il set completo di funzioni candidate include tutte le dichiarazioni sintetizzate e tutte le funzioni non-template sovraccaricate con lo stesso nome. Le dichiarazioni sintetizzate vengono trattate come qualsiasi altra funzione nel resto della risoluzione di sovraccarico, ad eccezione di quanto esplicitamente indicato in 13.3.3.

Nel caso della tua domanda, i sovraccarichi finiscono per essere indistinguibili (di credito: @Piotr S). In tali casi si applica "ordinamento parziale" (§14.5.6.2): ​​

F1 e F2 sono specializzazioni funzione di modello, e il modello di funzione per la F1 è più specializzata rispetto al modello per F2

Nota che le cose possono diventare piuttosto complicate, quando ad esla versione "modello aperto" ha preso uno T& anziché T const& (i riferimenti non const sono preferiti, a parità di tutti gli altri).

Quando hai avuto diversi overload che finiscono per avere lo stesso "rango" per la risoluzione di sovraccarico, la chiamata viene mal formate e il compilatore in grado di diagnosticare una funzione chiamata ambigua.

+2

Non è * scegliere la migliore corrispondenza * come nel classificare le conversioni. È un ordinamento parziale che fa sovraccaricare quest'ultimo il preferito per un argomento boost :: variant. –

+0

@PiotrS. Penso che la tua risposta sia in contrasto con la sezione citata. Inoltre, non sono sicuro che l'ordine di acquisto sia un problema con sovraccarichi dichiarati all'interno della stessa classe. (Questo trucco è spesso usato per le spedizioni ricorsive/variadiche che non funzionerebbero nello scope namespace) – sehe

+2

cosa è contrario alla sezione quotata? dopo aver istanziato entrambi i modelli di funzione sono indistinguibili l'uno dall'altro, quindi PO viene considerato: "* F1 e F2 sono specializzazioni di modelli di funzione e il modello di funzione per F1 è più specializzato del modello per F2 in base alle regole di ordinamento parziale descritte in 14.5 .6.2. "* –

3

La sezione chiave è in [temp.deduct.partial]:

due serie di tipi sono usati per determinare l'ordinamento parziale. Per ciascuno dei modelli coinvolti c'è il tipo di funzione originale e il tipo di funzione trasformata. [Nota: la creazione del tipo trasformato è descritta in 14.5.6.2. -end note] Il processo di deduzione utilizza il tipo trasformato come argomento modello e il tipo originale dell'altro modello come modello di parametro. Questo processo viene eseguito due volte per ciascun tipo coinvolto nel confronto di ordinamento parziale: una volta utilizzando il modello trasformato-1 come modello di argomento e modello-2 come modello di parametro e utilizzando nuovamente il modello trasformato-2 come modello di argomento e template-1 come modello di parametro.

Questo è davvero denso, anche per lo standard C++, ma ciò che significa in pratica è questo. Prendere le nostre due overload:

template <class T> // #1 
size_t operator()(const T& t) const 

template <typename... T> // #2 
size_t operator()(const boost::variant<T...>& t) 

E abbiamo intenzione di assegnare in pratica un certo tipo unico (s) a ciascuno e provare a vedere se l'altro si applica. Quindi prendiamo un po 'di tipo A per il #1 e B,C,D per #2. operator()(const A&) funziona per #2? No. operator()(const boost::variant<B,C,D>&) funziona per #1? Sì. Pertanto, le regole di ordinamento parziale indicano che #2 è più specializzato di #1.

E così, da [temp.func.order]:

Il processo di deduzione determina se uno dei modelli è più specializzata rispetto agli altri. Se così, il modello più specializzato è quello scelto dal processo di ordinazione parziale.

E da [over.match.best]:

[A] funzione valida F1 è definita come una funzione migliore di un'altra funzione vitale F2 se
- [..]
- F1 e F2 sono specializzazioni del modello di funzione e il modello di funzione per F1 è più specializzato rispetto al modello per F2 in base alle regole di ordinamento parziale descritte d in 14.5.6.2.

Pertanto, #2 deve essere scelto in ogni caso dove si applica. Se GCC sceglie #1, questo è un comportamento non conforme ed è un bug.

+1

molto ben spiegato! Grazie – rightaway717

Problemi correlati