2013-08-11 30 views
10

Il seguente codice dispecializzazione parziale per modello variadic necessita primo parametro di modello non variadic

#include <iostream> 
#include <utility> 

template<typename F, typename... T> 
struct Wrapper{ }; 

template<typename T> 
struct is_wrapper : std::false_type {}; 

template<typename... T> 
struct is_wrapper<Wrapper<T...>> : std::true_type {}; 

//template<typename F, typename... T> 
//struct is_wrapper<Wrapper<F, T...>> : std::true_type {}; 

int main() 
{ 
    Wrapper<int, double> w; 

    std::cout << is_wrapper<decltype(w)>::value << std::endl; 
} 

stampe 0. Tuttavia, se uno uncomments le due linee nel mezzo si stampe 1.

Perché doesn' t stampa sempre 1? La seconda specializzazione parziale non dovrebbe riguardare anche il caso apparentemente coperto solo dalla terza specializzazione parziale (commentata)?

risposta

1

Il codice deve effettivamente corrispondere alla specializzazione parziale; Lo standard non lo ha mai negato, ma i compilatori ci hanno messo un po 'a implementare correttamente i modelli variadici e la loro deduzione. GCC si conforma da 4.9.0 e Clang a partire da 3.6. Il bug report relativo a Clang è #22191 (non riesco a trovare GCC, però).

0

Normalmente quando scrivo modelli che sarebbero specializzati, uso prima una dichiarazione forward e dichiaro che i casi appartengono a specializzazioni. Nel tuo caso, capisco che stai provando a scrivere un modello variadico senza il caso vuoto (vale a dire, un modello variadich che potrebbe avere almeno un tipo).

Il tuo codice mi ha sorpreso perché penso che tu abbia ragione, la specializzazione variadic completa della tua caratteristica corrisponde ai casi di buco ... Per prima cosa ho provato ad usare una dichiarazione in avanti della tua classe di tratto, e definire SOLO il full-variadic specializzazione (Quindi se il parametro del carattere non è un'istanza Wrapper, la compilazione fallisce). E questo è esattamente ciò che è occurred, mi deludere ancora una volta:

#include <iostream> 
#include <utility> 

template<typename F , typename... T> 
struct Wrapper {}; 

template<typename T> 
struct is_wrapper; 

//template<typename T> 
//struct is_wrapper : std::false_type {}; 

template<typename... T> 
struct is_wrapper<Wrapper<T...>> : std::true_type {}; 

//template<typename F, typename... T> 
//struct is_wrapper<Wrapper<F, T...>> : std::true_type {}; 

using my_wrapper_type = Wrapper<int,double>; 

int main() 
{ 
    std::cout << std::boolalpha << is_wrapper<my_wrapper_type>::value << std::endl; 
}//"Invalid use of incomplete type" ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

Infine ho provato con il metodo dichiarazione anticipata della classe Wrapper. E sorprendentemente, funziona:

#include <iostream> 
#include <utility> 

template<typename... T> 
struct Wrapper; 

template<typename F, typename... T> 
struct Wrapper<F,T...>{ }; 


template<typename T> 
struct is_wrapper : std::false_type {}; 

template<typename... T> 
struct is_wrapper<Wrapper<T...>> : std::true_type {}; 

//template<typename F, typename... T> 
//struct is_wrapper<Wrapper<F, T...>> : std::true_type {}; 


using my_wrapper_type = Wrapper<int,double>; 

int main() 
{ 
    std::cout << std::boolalpha << is_wrapper<my_wrapper_type>::value << std::endl; 
} 

Questo stampa:

veri

Here è il codice in esecuzione in Ideone.

Cordiali saluti, non capisco perché il tuo codice fallisce e il mio funziona. È un bug del compilatore o c'è qualcosa che ci manca? Non lo so.

+0

La differenza è il numero di parametri del modello per il modello di classe 'Wrapper'. La tua (seconda) versione ha un solo parametro template, mentre la versione OP ha due parametri. La tua specializzazione parziale 'struct Wrapper ' non lo cambia. – dyp

+0

@DyP OK, ma se si dispone di un modello con due parametri (un parametro modello normale e un parametro modello variadic) e si passa un pacchetto variadic a questo modello, il pacchetto variadic non deve espandersi corrispondente al primo parametro normale, e il secondo parametro (il parametro variadic)?Questo è quello che non capisco, perché il branco non è espanso in quel modo. – Manu343726

+0

Sto ancora cercando di capire dove (e perché) lo Standard proibisce la specializzazione parziale per far corrispondere il pacchetto di parametri in questo caso. Immagino che sia da qualche parte intorno a [temp.deduct.type]/9. (L'espansione del pacchetto è diversa dalla deduzione.) – dyp

0

Se ho capito bene il vostro problema è solo una priorità di specializzazione,

is_wrapper<decltype(w)> 

Può essere specializzate per 2 modello:

template<typename T> // exact specialization 
template<typename... T> // variadic specialization with one parameter 

In questo caso compilatore scegliere in via prioritaria la specializzazione esatto e così template non è mai istatiate nel tuo caso.

+0

Che non è corretto. Le specializzazioni parziali sono sempre preferite ai modelli primari (e comunque devono essere più specializzati), vedi §14.5.5.1. – Columbo

Problemi correlati