2016-04-05 21 views
6

GCC (5.3) & Clang (3.8) cho rằng dòng đầu tiên trong test là xấu, nhưng thứ hai là tốt. MSVC (2015.2) cho biết, cả hai đều không hợp lệ.constexpr mẫu đối số weirdness

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 
} 

Điều gì, chính xác, theo tiêu chuẩn, là sự khác biệt? Mã này có hợp pháp để bắt đầu không?


lỗi kêu vang cho dòng đầu tiên:

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. 

lỗi 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

Bạn có thể cho chúng tôi biết lỗi nào bạn nhận được không? –

+0

Tôi không quá thoải mái khi đăng bức tường văn bản ở đây, nhưng đây là ý chính của nó. Dòng thứ hai trong MSVC: "'std :: get': không tìm thấy hàm trùng lặp nào phù hợp". Dòng đầu tiên: tất cả các loại mumbo-jumbo thông thường dọc theo các dòng tương tự trỏ đến nội bộ 'std :: tuple'. – vpozdyayev

+1

@vpozdyayev Các lỗi giúp ích rất nhiều - đó là thông báo lỗi khiến tôi hiểu vấn đề là gì. Nó không chỉ là mumbo-jumbo. – Barry

Trả lời

6

tl; dr Tôi nghĩ gcc và kêu vang của hành vi trong cả hai trường hợp là đúng.


Có sự khác biệt nhỏ giữa hai cuộc gọi của bạn. Hãy để tôi chỉ cần thêm một bí danh để minh họa:

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

Khi bạn viết:

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

Zero() là một loại . Nó là một hàm rỗng trả về một Zero. Như vậy, bạn đang gọi phiên bản std::get có loại: std::get<T>(). Vì không có phần tử nào trong tuple có loại Zero(), đây là lỗi.

Mặt khác, khi bạn viết:

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

n không phải là một loại - đó là duy nhất một giá trị. Kể từ std::integral_constant có một số constexpr operator size_t(), số đó được sử dụng và bạn gọi đến số std::get<I>(), thực hiện những gì bạn mong đợi.

Điều tương tự có thể được thực hiện bằng cách đơn giản bằng cú đúp khởi cũng như:

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

từ Zero{} chắc chắn không phải là một kiểu.

+1

Ah, phân tích cú pháp vexing tốt nhất của ol) :) ... C++ đã trở nên rất thuận tiện trong những năm gần đây mà tôi hoàn toàn quên mất điều đó. – vpozdyayev

+0

Thực ra ... Dòng 'std :: get (tuple);' chỉ hoạt động trong Clang chứ không phải GCC ("giá trị của 'n' không thể sử dụng trong biểu thức hằng"/"'n' không được khai báo 'constexpr' "). Đó có phải là lỗi của GCC không? – vpozdyayev

+0

@vpozdyayev Nó được dự định là một phiên bản tóm tắt của trường hợp làm việc của bạn, không thực sự là mã hợp lệ. – Barry

Các vấn đề liên quan