2013-02-16 27 views
10

Hãy nhìn vào đoạn mã sau:std :: map <> :: chèn sử dụng đối tượng không copyable và thống nhất khởi

#include <utility> 
#include <map> 

// non-copyable but movable 
struct non_copyable { 
    non_copyable() = default; 

    non_copyable(non_copyable&&) = default; 
    non_copyable& operator=(non_copyable&&) = default; 

    // you shall not copy 
    non_copyable(const non_copyable&) = delete; 
    non_copyable& operator=(const non_copyable&) = delete; 
}; 

int main() { 
    std::map<int, non_copyable> map; 
    //map.insert({ 1, non_copyable() }); < FAILS 
    map.insert(std::make_pair(1, non_copyable())); 
    //^same and works 
} 

Biên dịch đoạn này không thành công khi uncommenting dòng rõ rệt trên g ++ 4.7. Lỗi được tạo ra cho biết rằng không thể sao chép non_copyable nhưng tôi đã dự kiến ​​nó sẽ được di chuyển.

Tại sao chèn std::pair được xây dựng bằng cách khởi tạo đồng bộ không thành công nhưng không được xây dựng bằng cách sử dụng std::make_pair? Cả hai đều không phải sản xuất các giá trị có thể được chuyển thành công vào bản đồ?

Trả lời

17

[Đây là ghi đè hoàn chỉnh. câu trả lời trước đây của tôi không có gì để làm với các vấn đề]

Các map có hai liên quan insert quá tải:.

  • insert(const value_type& value), và

  • <template typename P> insert(P&& value).

Khi bạn sử dụng trình khởi tạo danh sách đơn giản map.insert({1, non_copyable()});, tất cả các tình trạng quá tải có thể được xem xét. Nhưng chỉ có cái đầu tiên (cái lấy const value_type&) được tìm thấy, vì cái kia không có ý nghĩa (không có cách nào để kỳ diệu đoán rằng bạn muốn tạo ra một cặp). Lần đầu tiên trên ­ tải không hoạt động do khóa học của bạn không thể sao chép được.

Bạn có thể làm cho công việc quá tải thứ hai bằng cách tạo ra các cặp một cách rõ ràng, hoặc là với make_pair, như bạn đã mô tả, hoặc bằng cách đặt tên các loại giá trị một cách rõ ràng:

typedef std::map<int, non_copyable> map_type; 

map_type m; 
m.insert(map_type::value_type({1, non_copyable()})); 

Bây giờ danh sách-initializer biết để tìm kiếm map_type::value_type nhà thầu, tìm thấy mova ­ ble có liên quan và kết quả là cặp giá trị liên kết với hàm P&& -overload của hàm insert.

(Một lựa chọn khác là sử dụng emplace() với piecewise_constructforward_as_tuple, dù rằng sẽ nhận được rất nhiều tiết hơn.)

Tôi cho rằng đạo đức ở đây là danh sách-initializers tìm kiếm quá tải khả thi – nhưng họ phải biết Bạn cần tìm gì!

+1

Vâng, đó là những gì tôi đã viết trước khi xóa câu trả lời của mình. Tôi có một nghi ngờ mặc dù: tại sao là một 'initializer_list <>' tạo ra ở đây? 'std :: pair ' dường như không có một hàm tạo. Tôi nghĩ cú pháp khởi tạo đồng bộ sẽ chỉ chọn hàm tạo thông thường của 'cặp <>'. –

+1

Ngoài ra, các yếu tố initializer_list <> phải là tất cả cùng loại, phải không? – eladidan

+0

+1 cho cả hai nhận xét. Thậm chí không nên có một 'initializer_list' trong ví dụ của tôi. Nó giống như một cuộc gọi đến constructor 'std :: pair' bằng cách khởi tạo đồng bộ. – mfontanini

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