2016-02-21 39 views
5

Sau khi đọc một bài viết tuyệt vời True Story: Efficient Packing tôi cố gắng thực hiện tuple bởi bản thân mình như tập thể dục:Gọi đến chức năng là mơ hồ khi loại không thích hợp định nghĩa là bí danh

#include <type_traits> 
#include <utility> 
#include <functional> 

template< std::size_t I, typename T > 
struct tuple_leaf { T value; }; 

template< std::size_t I, typename T > 
T & get(tuple_leaf< I, T > & leaf) 
{ return leaf.value; } 

template< typename Is, typename ...Ts > 
struct tuple_base; 

template< std::size_t ...Is, typename ...Ts > 
struct tuple_base< std::index_sequence<Is...>, Ts... > 
    : tuple_leaf< Is, Ts >... 
{ 
    using tuple_base_t = tuple_base; 
    template< typename ...Args, typename = std::enable_if_t< (sizeof...(Ts) == sizeof...(Args)) > > 
    tuple_base(Args &&... args) 
     : tuple_leaf< Is, Ts >{std::forward<Args>(args)}... 
    { ; } 
}; 

#if 0 
template< typename ...Ts > 
struct tuple 
    : tuple_base< std::index_sequence_for<Ts...>, Ts... > 
{ 
    using tuple_base_t = typename tuple::tuple_base_t; 
    using tuple_base_t::tuple_base_t; 
    using tuple_base_t::operator = ; 
}; 
#else 
// terse 
template< typename ...Ts > 
using tuple = tuple_base< std::index_sequence_for<Ts...>, Ts... >; 
#endif 

template< typename ...Args > 
tuple< Args &&... > 
forward_as_tuple(Args &&... args) 
{ return {std::forward<Args>(args)...}; } 

#include <tuple> 

int 
main() 
{ 
    tuple<int> t(1); 
    auto f = forward_as_tuple(t); 
    (void)f; 
    return 0; 
} 

Live example

Sau khi thực hiện forward_as_tuple tôi quyết định thay đổi định nghĩa của tuple loại từ mẫu lớp đến mẫu bí danh của mẫu lớp cơ sở của nó, bởi vì tất cả những gì tôi cần tách thành lớp tuple chính nó và lớp triển khai thực hiện tuple_base chỉ là std::index_sequence_for đối với gói thông số loại mẫu có biến thể - mẫu bí danh là công cụ phù hợp chính xác cho mục đích này. Sau khi thực hiện mà tôi nhận được một lỗi (#if 0 trường hợp):

error: call to 'forward_as_tuple' is ambiguous

Có vẻ lạ đối với tôi, vì alias mẫu làm gì cả và mặt khác forward_as_tuple gọi cho loại hình từ không gian tên tương tự - Tôi đã hy vọng rằng ADL nên làm việc cho trường hợp trên chắc chắn.

Cách giải thích sự khác biệt giữa các phiên bản mã #if 1#if 0?

+0

'std :: index_sequence_for' trở thành một đối số mẫu kiểu của loại đối số của một cuộc gọi hàm, do đó,' std' được kiểm tra bởi ADL. BTW. Bạn sẽ gặp lỗi tương tự nếu bạn sử dụng 'tuple ' trực tiếp –

+0

@PiotrSkotnicki Khoảnh khắc tinh tế. Tôi luôn ghi nhớ rằng ADL chỉ dành cho các kiểu đối số hàm, nhưng cũng cho các tham số mẫu. – Orient

+0

@PiotrSkotnicki 'tuple_base , int>>, tuple_base , int>>' là đối số hàm. 'std :: index_sequence_for' nằm sâu bên trong. I E. nó không phải là tên mẫu hàng đầu. Nó có quan trọng không? – Orient

Trả lời

3

Tra cứu nguyên nhân Adl theo loại được chuyển và đối số mẫu của loại được chuyển.

Không có bí danh tuple có các loại và chính nó là những nơi cần tìm ADL.

Trường hợp bí danh tuple có std::index_sequence trong danh sách đối số mẫu của nó. Điều này làm cho std::forward_as_tuple được xem xét, ngoài forward_as_tuple của bạn. Họ là những trận đấu tốt, và sự mơ hồ xảy ra.

Như @Piotr đã lưu ý ở trên trong các nhận xét, tuple<std::string> hiển thị vấn đề này ngay cả trong trường hợp không phải bí danh.

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