2016-03-02 12 views
14

consideri il codice seguente:Perché l'idioma di rilevamento void_t <> non funziona con gcc-4.9?

#include <iostream> 
#include <type_traits> 

struct Test { Test& operator++(); }; 
struct NoIncrement { }; 

template <typename...> using void_t = void; 

template <class, class=void_t<>> 
struct has_pre_increment_member : std::false_type { }; 

template <class T> 
struct has_pre_increment_member<T, void_t<decltype(++std::declval<T&>())>> 
    : public std::true_type { }; 

int main() { 
    std::cout << has_pre_increment_member<Test>::value << " "; 
    std::cout << has_pre_increment_member<NoIncrement>::value << std::endl; 
} 

Con g ++ versione 5 e successive (e la -std = C++ 14 bandiera, ovviamente), queste uscite codice

1 0 

come dovrebbe. Con g ++ versione 4.9 (e la -std = C++ 14 bandiera), tuttavia, è in uscita

1 1 

Entrambi pretesa di essere utilizzando lo stesso linguaggio standard, quindi qual è il problema qui?

+2

Stai usando 4.9.0 o è superiore a quello? Ho visto alcuni bug in 4.9.0 che sono stati risolti se si passa a 4.9.2. – NathanOliver

+0

4.9.3 per essere esatti –

+0

Beh, questo era tutto ciò che potevo contribuire. se ti fa cadere meglio, funziona anche con clang. – NathanOliver

risposta

16

Questo deriva come risultato di CWG Issue 1558 ed è ora considerato un bug in gcc (in particolare 64395 - attualmente risolto). L'idea alla base del problema è che, poiché in realtà non utilizzare i parametri del modello qui:.

template <typename...> using void_t = void; 

non c'è fallimento sostituzione indipendentemente da quali tipi o espressioni si tenta di passare in

Per fortuna, c'è un soluzione facile che non comporta l'aggiornamento del compilatore. Possiamo riscrivere void_t utilizzare effettivamente sua confezione parametro, innescando in tal modo il fallimento di sostituzione:

namespace void_details { 
    template <class... > 
    struct make_void { using type = void; }; 
} 

template <class... T> using void_t = typename void_details ::make_void<T...>::type; 

Che farò il vostro esempio fare la cosa giusta in tutte le versioni di gcc che ho provato.