2015-10-17 29 views
12

Il codice seguente viene compilato con VS15 Community e stampa "Hello".Comportamento imprevisto con alias del tipo di modello in VS2015

#include <functional> 
#include <iostream> 

template<typename T> 
using void_template_alias_t = void; 

template<typename T> 
using Func = std::function<void(T)>; 

template<typename T> 
using FuncVoid = Func<void_template_alias_t<T>>; 

int main() 
{ 
    FuncVoid<void> hello = [] { std::cout << "Hello\n"; }; 
    hello(); 
} 

Penso che questo non è consentito compilare.

Stavo giocando, il codice era un po 'più complesso. Mi aspettavo ingenuamente che funzionasse, ma all'improvviso mi sono reso conto che questo codice non doveva essere compilato perché non è possibile creare uno Func<void> (o mi sbaglio di questo?).

  • Ho trovato una soluzione magica?
  • Si tratta di un nuovo comportamento dallo standard C++ 14?
  • O è semplicemente un bug del compilatore?

Modifica: la seguente versione semplificata non viene compilata.

#include <functional> 
#include <iostream> 

template<typename T> 
using Func = std::function<void(T)>; 

int main() 
{ 
    Func<void> hello = [] { std::cout << "Hello\n"; }; 
    hello(); 
} 
  • Allora perché il codice di cui sopra la compilazione e lavorando come mi aspettavo prima?
  • È un'implementazione corretta, in caso contrario, come sarebbe?
+0

C'è un mondo di differenza tra 'foo (void)' e 'using X = void; foo (X); '. Sarei sorpreso se altri compilatori lo accettassero. –

+0

Oh, ero troppo sicuro. Lo standard afferma che "La lista dei parametri' (void) 'è equivalente alla lista dei parametri vuota.", Ma non specifica che '(void)' è un testo letterale. E non c'è alcuna produzione grammaticale specifica, e sia g ++ che Visual C++ compilano 'void foo (X)' dove 'X' è un nome per' void', e compilano la chiamata 'foo()'. –

+0

Forse dovrei notare esplicitamente, che l'interpretazione in cui '(void)' si riferisce a una funzione in cui il * tipo * del singolo argomento è effettivamente 'void', e quindi denota una funzione senza argomenti, non funziona bene con il codice del template che richiama la funzione con un argomento, cioè non è pratico. Eppure sia MSVC che MinGW g ++ accettano il non-template 'foo (My_void)' e chiamano 'foo()'. :( –

risposta

5

Oppure è semplicemente un bug del compilatore?

Quello. Come già detto da @TC, CWG #577 è rilevante:

[...] ci fosse qualche preoccupazione espressa sul trattamento dei modelli di funzione e membri funzioni dei modelli di classe se la regola C++ sono stati modificati: per un parametro di modello T, una funzione che utilizza un singolo parametro di tipo T diventa una funzione senza parametro se è stata creata un'istanza con T = void?

Questa è una denuncia giustificata, ma peccato per te, le funzioni membro/templates funzione membro e tipo-id s sono stati colpiti allo stesso modo dalla risoluzione:

una lista di parametri che consiste di un singolo parametro senza nome di tipo non dipendente void equivale a un elenco di parametri vuoto.

quindi entrambi i frammenti sono mal formati, poiché il tipo di parametro è effettivamente dipendente.


E 'una corretta attuazione, se non, come sarebbe simile?

Non esiste un'implementazione corretta.Se hai bisogno di un tipo di funzione con un elenco di parametri vuoto, dovrai specificarlo indipendentemente dai parametri del modello.

Quindi perché il codice sopra è compilato e funzionante come previsto inizialmente?

La mia ipotesi migliore: VC++ fa la sostituzione di void_template_alias_t<T>dopo assicurando che il tipo di parametro non è un dipende tipo "cv void", ma prima di fare il "void -> Elenco trasformazione vuota". Tuttavia, è spesso difficile comprendere come VC++ (o qualsiasi compilatore, se è per questo) pensi internamente.

Problemi correlati