2015-06-11 7 views
8

Ich probiere Beispiele aus Walter Brown's TMP talk aus und ich versuche, seine has_member Implementierung funktioniert zu bekommen.Was macht SFINAE nicht korrekt mit der folgenden Funktion has_member?

jedoch die Umsetzung wahr zu fälschlicherweise scheint zurückzukehren was dazu führt, mich gibt es einige Details von SFINAE zu glauben, dass ich verstehen mich nicht.

#include <iostream> 
#include <type_traits> 

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

template <class, class = void> 
struct has_type_member: std::false_type {}; 

template <class T> 
struct has_type_member<T, void_t<typename T::type> >: std::true_type {}; 

struct FooWithType 
{ 
    typedef int type; 
}; 

struct FooNoType 
{ 
}; 

int main() 
{ 
    std::cout << "Does FooWithType have type member? " << 
     (has_type_member<FooWithType>() ? "YES" : "NO") << "\n"; 

    std::cout << "Does FooNoType have type member? " << 
     (has_type_member<FooNoType>() ? "YES" : "NO") << "\n"; 

    return 1;                             
}  

Ausgang ist:

Does FooWithType have type member? YES 
Does FooNoType have type member? YES 

Ich bin auf gcc 4.8.2 auf Ubuntu.

+1

Sind Sie sicher, dass Ihre void_t-Implementierung in Ordnung ist? So erinnere ich mich nicht, dass es umgesetzt wurde. Vielleicht ist es sogar für schlecht geformte Vorlagen leer? – KABoissonneault

+0

See [N3909] (http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2014/n3909.pdf), [N4436] (http://www.open-std.org /jtc1/sc22/wg21/docs/papers/2015/n4436.pdf) und [CWG 1558] (http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#1558) – dyp

+0

Verwandte/Duplikat: [C++ 11: SFINAE in Template-Parameter, GCC vs Clang] (http://stackoverflow.com/q/28282398/) – dyp

Antwort

11

Das Problem ist, dass gcc 4.8.2 (und vor gcc 5.0) nicht verwendete Argumente in Alias-Vorlagen nicht als für SFINAE geeignet betrachtet. Die Abhilfe ist auf eine voider Klassenvorlage zu übermitteln:

template <class ... T> struct voider { using type = void; }; 
template <class ... T> 
using void_t = typename voider<T...>::type; 

Von http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3911.pdf Abschnitt 2.3:

Ach, wir haben festgestellt Umsetzung Divergenz (Clang vs. GCC), während mit den über sehr einfachen Arbeits Definition. Wir (weiterhin) Vermutung, dass dies wegen der CWG Ausgabe ist 1558: „Die Behandlung von nicht verwendeten Argumenten in einer Alias ​​Template-Spezialisierung wird durch die derzeitige Wortlaut von 14.5.7 keine Angabe [temp.alias]“

+0

@dyp rechts, unbenutzte Standardargumente. Ich brauchte eine Weile, um den Wortlaut in Browns Papier zu finden. – ecatmur

+1

Gilt das immer noch für die neueren Versionen von GCC? – KABoissonneault

+1

@KABoissonneault gcc 5.0 und höher erfordert die Problemumgehung nicht. – ecatmur