2015-06-24 7 views
13

Bearbeiten Append: Der Titel der Frage war "haben Visual Studio Compiler oder Clang haben falsches Verhalten" - aber das wurde geändert.Benötigt der Standard std :: tuple_size, um SFINAE-freundlich zu sein?

Also füge ich hier, dass clang und gcc kompiliert es so, wie ich es vorhatte, aber VS nicht.

Ich habe den folgenden Code:

template<typename S, typename T, std::size_t... I> 
    void 
    print_tuple_like(S& s, const T& t, std::index_sequence<I...>) 
    { 
    void* unused[] = { &(s << std::get<I>(t))... };  
    } 

template<typename S, typename T, 
     std::size_t N = std::tuple_size<decltype(T::children)>::value> 
    S& operator<<(S& s, const T& t) 
{ 
    print_tuple_like(s, t.children, std::make_index_sequence<N>{}); 
    return s; 
} 

und ich bekomme einen Compiler-Fehler:

1>c:\program files (x86)\microsoft visual studio 14.0\vc\include\utility(313): error C2338: The C++ Standard doesn't define tuple_size for this type. 
1> c:\users\jonas\documents\visual studio 2015\projects\consoleapplication7\consoleapplication7\consoleapplication7.cpp(36): note: see reference to class template instantiation 'std::tuple_size<unknown-type>' being compiled 
1> c:\users\jonas\documents\visual studio 2015\projects\consoleapplication7\consoleapplication7\consoleapplication7.cpp(43): note: see reference to function template instantiation 'void print_tuple_like<S,std::tuple<Signature::A,Signature::B>,0,1>(S &,const T &,std::integer_sequence<_Ty,0,1>)' being compiled 
1>   with 
1>   [ 
1>    S=std::ostream, 
1>    T=std::tuple<Signature::A,Signature::B>, 
1>    _Ty=size_t 
1>   ] 
1> c:\users\jonas\documents\visual studio 2015\projects\consoleapplication7\consoleapplication7\consoleapplication7.cpp(50): note: see reference to function template instantiation 'S &operator <<<std::ostream,Signature,2>(S &,const T &)' being compiled 
1>   with 
1>   [ 
1>    S=std::ostream, 
1>    T=Signature 
1>   ] 

Das liegt daran, dass der folgende Code in Visual Studio:

// TEMPLATE STRUCT tuple_size 
template<class _Tuple> 
struct tuple_size { // size of non-tuple 
    static_assert(_Always_false<_Tuple>::value, "The C++ Standard doesn't define tuple_size for this type."); 
}; 

das machen Substitutionsfehler in einen harten Fehler - die SFINAE SFIAE

machen

Wenn ich

static_assert(_Always_false<_Tuple>::value, "The C++ Standard doesn't define tuple_size for this type."); 

es funktioniert entfernen.

Ist der Code die C++ - Standardregeln? Oder ist Microsoft falsch?

+0

Das ist ein ziemlich intensiver Code dort. Was versuchst du zu erreichen? – tadman

+0

Wenn ich eine Klasse mit einem Mitglied namens childs habe, das ein Tupel ist, sollte das Tupel iteriert werden und die Kinder << streamed –

+0

Alle Vorschläge für einen alternativen Ansatz ist auch willkommen :) –

Antwort

1

Der Standard schreibt vor, dass tuple_sizenicht freundlich SFINAE, aber this is considered by many to be a defect, and looks on-track to be fixed in C++17.

Es ist erforderlich, dass alle Spezialisierungen (die im Standard für "Template-Instanziierungen" sprechen) von tuple_size grundsätzlich std::integral_constant<size_t, ?> sind oder davon erben. (Es bleibt dem Compiler etwas Freiheit)

Wenn das primäre Template nicht definiert ist, verletzt es das nicht. Wenn die primäre Vorlage jedoch als leere Struktur (oder ähnlich) definiert ist, dann ist diese leere Struktur eine Vorlageninstanz (die der Standard "Spezialisierung" nennt), die im Wesentlichen nicht std::integral_constant<size_t, ?> ist.

Durch meine Lesung wäre es legal für die primäre Vorlage (der "Fehler" -Fall), std::integral_constant<size_t, 42> oder eine andere Konstante zu sein. Nutzlos und böse, aber legal. Aber eine leere Struktur zu sein verstößt gegen den Standard.

Die Argumente dagegen, dies zu ändern, um eine leere Struktur zu beauftragen, sind über den Wortlaut, und nicht darüber, ob es eine gute Idee ist.

Dank @ T.C. Wer hat das in einem Kommentar Thread auf eine andere Antwort hier gelöst.

6

N4140 20.4.1 tuple_size ‚s nicht spezialisierte Version wie beschrieben:

template <class T> class tuple_size; // undefined 

durch eine Definition, die MSVC lib hat den Standard verletzt.

Sie sollten jedoch wissen, dass Ihre Frage nicht die beteiligten Compiler betrifft, sondern die Standard-Bibliotheksimplementierungen.

+0

kann jemand besser mit der standardischen Bedeutung von "undefined" in diesem Fall bestätigen? –

+1

Sie sind genau richtig. "Undefiniert" bedeutet in diesem Fall "keine Definition", d.h. "kein Klassenkörper". – o11c

+0

In meiner Kopie von N4140 heißt es nicht "undefined", es besagt nur, dass alle ** Spezialisierungen ** die Anforderungen von "UnaryTypeTraits" erfüllen müssen. Was keine Aussage über die Basisvorlage macht. –

0

Könnte so etwas mit einigen Modifikationen funktionieren?

template<typename S, typename T, typename tuple_element<0,decltype(T::children)>::type > 
    S& operator<<(S& s, const T& t)