2016-04-05 17 views
6

GCC (5.3) & Clang (3.8) afferma che la prima riga in test non è buona, ma la seconda è soddisfacente. MSVC (2015.2) dice che entrambi non sono validi.argomento modello constexpr stranozza

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 
} 

Cosa, esattamente, secondo lo standard, è la differenza? Questo codice è legale per cominciare?


errore clang per la prima riga:

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. 

errore gcc:

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

Potete dirci per favore quali errori si ottengono? –

+0

Non sono a mio agio nel postare pareti di testo qui, ma ecco il senso. Seconda riga sotto MSVC: "'std :: get': nessuna funzione di overloading trovata trovata". Prima riga: tutti i generi del solito mumbo-jumbo lungo linee simili che puntano agli interni di 'std :: tuple'. – vpozdyayev

+1

@vpozdyayev Gli errori aiutano molto - sono i messaggi di errore che mi hanno portato a capire quale fosse il problema. Non è solo mumbo-jumbo. – Barry

risposta

6

tl; dr penso gcc e clang di comportamento in entrambi i casi è corretta.


C'è una sottile differenza tra le due chiamate. Vorrei solo aggiungere un alias per illustrare:

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

Quando si scrive:

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

Zero() è un tipo . È una funzione nulla che restituisce un valore Zero. Pertanto, stai chiamando la versione di std::get che accetta un tipo: std::get<T>(). Poiché non esiste alcun elemento in con tipo Zero(), si tratta di un errore.

D'altra parte, quando si scrive:

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

n non è un tipo - è sempre e solo un valore. Dal momento che std::integral_constant ha uno constexpr operator size_t(), che uno si abitua e si finisce per chiamare std::get<I>(), che fa quello che ti aspetteresti.

Lo stesso potrebbe essere realizzato semplicemente usando inizializzazione tutore così:

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

poiché Zero{} non è sicuramente un tipo.

+1

Ah, il buon ol 'esempio più irritante :) ... C++ è diventato così conveniente negli ultimi anni che mi sono totalmente dimenticato di QUESTO. – vpozdyayev

+0

In realtà ... 'std :: get (tupla);' line funziona solo in Clang, ma non in GCC ("il valore di 'n' non è utilizzabile in un'espressione costante"/"'n' non è stato dichiarato 'constexpr' "). Sarebbe un bug GCC? – vpozdyayev

+0

@vpozdyayev Doveva essere una versione ridotta del tuo caso di lavoro, non un codice effettivamente valido. – Barry