2012-12-31 4 views
6

Questo codice non riesce a compilare nella maggior parte dei compilatori, ma in un primo momento ho intuitivamente dovrebbe SFINAE per proteggere me:SFINAE, deduzione vs. instanziazione

typedef void (*A)(); 

template < typename T > 
struct a_metafun { typedef typename T::type type; }; 

template < typename T > 
typename a_metafun<T>::type f(T) {} 

template < typename T> 
void f(T(*)()) {} 

int main() { f(A()); } 

posso risolvere il problema in almeno due modi:

1) Modificare la definizione di "metafun" f() per:

template < typename T > typename T::type f(T) {}

2) definiscono "a_metafun" tale che analizza T e ha un tipo, se T ha uno e non fa i f non lo fa ... ma un'istanza senza errori in entrambi i casi:

BOOST_MPL_HAS_XXX_TRAIT_DEF(type) 

typedef < template T, bool = has_type<T>::value > 
struct a_metafun { }; 

typedef < template T > 
struct a_metafun<T, true> { typedef typename T::type type }; 

Upon guardando 14.8.2 (C++ 03) sembra a me come specifica esattamente in quali condizioni può applicare SFINAE. C'è un posto migliore per guardare? Il fallimento nell'istanziazione di un modello già dedotto, anche durante la deduzione di un altro, non sembra essere incluso in questo elenco.

Un'altra direzione che ho preso per interpretare ciò che rende questo illegale è che la detrazione di a_metafun è già avvenuta e l'istanziazione dei suoi interni è ciò che sta causando l'errore. SFINAE non si applica durante l'istanziazione ma solo durante la deduzione o mi sbaglio? Nel secondo caso però, a_metafun è stato correttamente e istanziato con una buona struttura, ma semplicemente non ha una definizione di "tipo" all'interno, il che significa che il modello che tenta di creare un'istanza non riesce a causa della sostituzione.

Fondamentalmente mi sto chiedendo cosa nello standard specifica il comportamento a cui sto assistendo. Ogni compilatore che ho provato si lamenta, anche con il comeau. Sono dell'opinione che abbiano ragione nel farlo, non sono completamente sicuro del perché.

Quindi, esperti ... che cosa è? Perché l'istanziazione del tipo, anche nel contesto della deduzione in f() causa un errore piuttosto che l'esclusione di SFINAE?

+0

Penso che dovrebbe fallire in C++ 11, non in C++ 03 però. La regola SFINAE (o meglio le * wordings *) è leggermente cambiata in C++ 11. – Nawaz

risposta

2

SFINAE non vi proteggerà lì, l'errore si verifica dopo tipo deduzione. Tuttavia, questo dovrebbe funzionare:

template < typename T, typename Type = typename T::type > 
struct a_metafun { typedef Type type; }; 

Con accesing T::type in un parametro di template di default causiamo che questo accada in fase di sostituzione, e in quel momento SFINAE calci in

Edit:. Dopo averci un po 'di più, non sono esattamente sicuro del motivo per cui la tua attuale implementazione fallisce. Penso che sia perché a_metafunha un tipo di membro type, uno che causa un errore di compilazione; sarebbe diverso se a_metafun non avesse affatto un tipo membro type.

+0

Vedere la mia risposta perché non funziona in C++ 11. – Nawaz

4

nella specifica C++ 03, la regola di SFINAE è un po 'vago, permettendo agli autori del compilatore di andare a qualsiasi lunghezza di trovare mancata sostituzione di provocare SFINAE. Il testo pertinente §14.8.2/2 da C++ 03 dice,

- [...] Se una sostituzione in un parametro di modello o il tipo di funzione dei risultati dei modelli in funzione di un tipo non valido, la deduzione di tipo non riesce [...]

Spiega inoltre alcuni motivi di errore, ma nessuno di essi in realtà dice a che punto l'errore di sostituzione dovrebbe essere considerato come SFINAE. Quindi immagino che il tuo codice possa funzionare bene in C++ 03 (o no, a seconda di come gli autori del compilatore interpretano il testo, ma mi confonde comunque).

Ma le diciture in C++ 11 sono state migliorate rimuovendo la vaghezza. Dice in §14.8.2/8,

Se una sostituzione risulta in un tipo o un'espressione non valida, digitare la deduzione non riesce. Un tipo o un'espressione non valida è uno che sarebbe mal formato se scritto usando gli argomenti sostituiti. [Nota: il controllo dell'accesso viene eseguito come parte del processo di sostituzione. -end note] Solo i tipi e le espressioni non validi in nel contesto immediato del tipo di funzione e i relativi tipi di parametri del modello possono causare un errore di deduzione.

Il termine "contesto immediato" è interessante, e credo che si applica alla vostra situazione. Più specificamente, l'errore di sostituzione nella funzione meta a_metafun non viene considerato "contesto immediato" del tipo di funzione. È mal formato in C++ 11, non in SFINAE.

La definizione di "contesto immediato" non è abbastanza chiara in C++ 11. Ecco un problema attivo:

+1

Interessante davvero! Non ero a conoscenza di questo cambiamento in _SFINAE_. Grazie –