2016-04-05 5 views
6

GCC (5.3) & Clang (3.8) behaupten, dass die erste Zeile in test ist schlecht, aber die zweite ist in Ordnung. MSVC (2015.2) sagt, beide sind ungültig.conexpr Vorlage Argument Verrücktheit

template< typename N, typename T > 
void f(N n, T t) { std::get<n>(t); } 
void test() { 
    std::get< std::integral_constant< size_t, 0 >() >(std::make_tuple(123)); // not ok 
    f(std::integral_constant< size_t, 0 >(), std::make_tuple(123)); // ok for gcc, clang, but not msvc 
} 

Was genau, nach dem Standard, ist der Unterschied? Ist dieser Code überhaupt legal?


Klirren Fehler für die erste Zeile:

In file included from main.cpp:2: 
/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/5.3.0/../../../../include/c++/5.3.0/tuple:874:34: error: no matching function for call to '__get_helper2' 
    { return std::forward<_Tp&&>(std::__get_helper2<_Tp>(__t)); } 
           ^~~~~~~~~~~~~~~~~~~~~~~ 
main.cpp:10:10: note: in instantiation of function template specialization 'std::get<std::integral_constant<unsigned long, 0>(), int>' requested here 
    std::get<std::integral_constant<size_t, 0>()>(std::make_tuple(123)); // not ok 
     ^
/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/5.3.0/../../../../include/c++/5.3.0/tuple:856:5: note: candidate template ignored: could not match '_Tuple_impl' against 'tuple' 
    __get_helper2(_Tuple_impl<__i, _Head, _Tail...>& __t) noexcept 
    ^
/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/5.3.0/../../../../include/c++/5.3.0/tuple:861:5: note: candidate template ignored: could not match '_Tuple_impl' against 'tuple' 
    __get_helper2(const _Tuple_impl<__i, _Head, _Tail...>& __t) noexcept 
    ^
1 error generated. 

gcc Fehler:

In file included from main.cpp:2:0: 
/usr/local/include/c++/5.3.0/tuple: In instantiation of 'constexpr _Tp&& std::get(std::tuple<_Elements ...>&&) [with _Tp = std::integral_constant<long unsigned int, 0ul>(); _Types = {int}]': 
main.cpp:10:75: required from here 
/usr/local/include/c++/5.3.0/tuple:874:57: error: no matching function for call to '__get_helper2(std::tuple<int>&)' 
    { return std::forward<_Tp&&>(std::__get_helper2<_Tp>(__t)); } 
                 ^
/usr/local/include/c++/5.3.0/tuple:856:5: note: candidate: template<class _Head, long unsigned int __i, class ... _Tail> constexpr _Head& std::__get_helper2(std::_Tuple_impl<__i, _Head, _Tail ...>&) 
    __get_helper2(_Tuple_impl<__i, _Head, _Tail...>& __t) noexcept 
    ^
/usr/local/include/c++/5.3.0/tuple:856:5: note: template argument deduction/substitution failed: 
/usr/local/include/c++/5.3.0/tuple:874:57: note: mismatched types 'std::integral_constant<long unsigned int, 0ul>()' and 'int' 
    { return std::forward<_Tp&&>(std::__get_helper2<_Tp>(__t)); } 
                 ^
/usr/local/include/c++/5.3.0/tuple:874:57: note: 'std::tuple<int>' is not derived from 'std::_Tuple_impl<__i, std::integral_constant<long unsigned int, 0ul>(), _Tail ...>' 
/usr/local/include/c++/5.3.0/tuple:861:5: note: candidate: template<class _Head, long unsigned int __i, class ... _Tail> constexpr const _Head& std::__get_helper2(const std::_Tuple_impl<__i, _Head, _Tail ...>&) 
    __get_helper2(const _Tuple_impl<__i, _Head, _Tail...>& __t) noexcept 
    ^
/usr/local/include/c++/5.3.0/tuple:861:5: note: template argument deduction/substitution failed: 
/usr/local/include/c++/5.3.0/tuple:874:57: note: mismatched types 'std::integral_constant<long unsigned int, 0ul>()' and 'int' 
    { return std::forward<_Tp&&>(std::__get_helper2<_Tp>(__t)); } 
                 ^
/usr/local/include/c++/5.3.0/tuple:874:57: note: 'std::tuple<int>' is not derived from 'const std::_Tuple_impl<__i, std::integral_constant<long unsigned int, 0ul>(), _Tail ...>' 
+0

Können Sie uns bitte sagen, welche Fehler Sie bekommen? –

+0

Ich bin nicht allzu wohl dabei, Textwände hier zu posten, aber hier ist der Kern davon. Zweite Zeile unter MSVC: "'std :: get': keine passende überladene Funktion gefunden". Erste Zeile: alle Arten des üblichen Hokuspokus entlang ähnlicher Linien, die auf die Interna von "std :: tuple" zeigen. – vpozdyayev

+1

@vpozdyayev Die Fehler helfen sehr - es sind die Fehlermeldungen, die mich dazu brachten zu verstehen, was das Problem war. Es ist nicht nur Hokuspokus. – Barry

Antwort

6

tl; dr Ich denke, gcc und Klirren das Verhalten in beiden Fällen korrekt ist.


Es gibt einen feinen Unterschied zwischen Ihren beiden Anrufen. Lassen Sie mich nur ein Alias ​​hinzufügen zu veranschaulichen:

using Zero = std::integral_constant<size_t, 0>; 
auto tuple = std::make_tuple(123); 

Wenn Sie schreiben:

std::get<Zero()>(tuple); 

Zero() einTyp ist. Es ist eine Nullfunktion, die einen Zero zurückgibt. Als solches rufen Sie die Version std::get an, die den folgenden Typ verwendet: std::get<T>(). Da in tuple kein Element mit dem Typ Zero() vorhanden ist, handelt es sich um einen Fehler.

Auf der anderen Seite, wenn Sie schreiben:

Zero n; 
std::get<n>(tuple); 

n ist kein Typ - es ist immer nur ein Wert. Da std::integral_constant einen constexpr operator size_t() hat, wird dieser benutzt und Sie rufen schließlich std::get<I>() auf, was das tut, was Sie erwarten würden.

std::get<Zero{}>(tuple); 

seit Zero{} ist auf jeden Fall eine Art nicht:

könnte das gleiche, indem einfach Klammer Initialisierung als auch erreicht werden.

+1

Ah, der gute alte Ärger parsen :) ... C++ wurde in den letzten Jahren so praktisch, dass ich das total vergessen habe. – vpozdyayev

+0

Eigentlich ... Die 'std :: get (Tupel);' Linie funktioniert nur in Clang, aber nicht GCC ("der Wert von 'n' ist nicht verwendbar in einem konstanten Ausdruck"/"'n' wurde nicht erklärt "consExpr")). Wäre das ein GCC-Fehler? – vpozdyayev

+0

@vpozdyayev Es sollte eine gekürzte Version Ihres Arbeitsfalls sein, kein tatsächlich gültiger Code. – Barry