2015-02-26 28 views
5

Chúng tôi có chức năng thuận tiện sau đây tìm nạp giá trị từ bản đồ hoặc trả lại giá trị mặc định dự phòng nếu không tìm thấy khóa.không cho phép chuyển tham chiếu rvalue sang hàm

template <class Collection> const typename Collection::value_type::second_type& 
    FindWithDefault(const Collection& collection, 
        const typename Collection::value_type::first_type& key, 
        const typename Collection::value_type::second_type& value) { 
     typename Collection::const_iterator it = collection.find(key); 
     if (it == collection.end()) { 
     return value; 
     } 
     return it->second; 
    } 

Vấn đề với chức năng này cho phép chuyển đối tượng tạm thời làm đối số thứ ba sẽ là lỗi. Ví dụ:

const string& foo = FindWithDefault(my_map, ""); 

Có thể không cho phép đi tham khảo rvalue với số thứ ba một cách nào đó bằng cách sử dụng std :: is_rvalue_reference và khẳng định tĩnh?

+0

Nó cảm thấy thực sự trực quan để vượt qua '" "' ở đó. Nó sẽ là tốt hơn để tìm một cách để ngăn chặn 'FindWithDefault' từ bị ràng buộc để tham khảo, ngoại trừ tôi không nghĩ rằng có một. Dù sao, nó sẽ là tốt hơn để chỉ đơn giản là làm cho 'foo' một giá trị trong ví dụ này. –

+1

Các vấn đề khác với câu hỏi này là bạn đã nhảy vào những gì bạn nghĩ là giải pháp, thay vì nêu rõ vấn đề. Khi làm như vậy, bạn đã tập trung vào các tham chiếu rvalue nhưng đó không phải là vấn đề duy nhất; một tham chiếu lvalue-to-'const'-tạm thời sẽ cắn bạn chỉ là khó khăn. Có lẽ lấy giá trị 'value' mặc định. –

+0

Bạn có thể trả về bằng giá trị thay vì trả lại bằng tham chiếu. Điều này có vẻ khá tự nhiên cho một tìm-với-mặc định. – galinette

Trả lời

6

Thêm quá tải bổ sung này nên làm việc (chưa được kiểm tra):

template <class Collection> 
const typename Collection::value_type::second_type& 
FindWithDefault(const Collection& collection, 
       const typename Collection::value_type::first_type& key, 
       const typename Collection::value_type::second_type&& value) = delete; 

độ phân giải quá tải sẽ chọn tình trạng quá tải này để tham khảo rvalue và = delete làm cho nó một lỗi thời gian biên dịch. Ngoài ra, nếu bạn muốn chỉ định một thông báo tùy chỉnh, bạn có thể đi cho

template <class Collection> 
const typename Collection::value_type::second_type& 
FindWithDefault(const Collection& collection, 
       const typename Collection::value_type::first_type& key, 
       const typename Collection::value_type::second_type&& value) { 
    static_assert(
     !std::is_same<Collection, Collection>::value, // always false 
     "No rvalue references allowed!"); 
} 

Các std::is_same đang có để làm cho static_assert phụ thuộc vào mẫu tham số, nếu không nó sẽ gây ra một lỗi biên dịch ngay cả khi tình trạng quá tải không được gọi .

EDIT: Đây là một hoàn chỉnh tối thiểu dụ:

void foo(char const&) { }; 
void foo(char const&&) = delete; 

int main() 
{ 
    char c = 'c'; 
    foo(c); // OK 
    foo('x'); // Compiler error 
} 

MSVC cung cấp cho các lỗi sau đây để cuộc gọi thứ hai để foo:

rval.cpp(8) : error C2280: 'void foo(const char &&)' : attempting to reference a deleted function 
     rval.cpp(2): See declaration of 'foo' 

Cuộc gọi đầu tiên, tuy nhiên, hoạt động tốt và nếu bạn bình luận ra thứ hai sau đó chương trình biên dịch.

+1

đối tượng tạm thời! = Tham chiếu rvalue. Bạn có thể có một const & đối tượng tạm thời. – user1095108

+0

@ user1095108: Đúng, nhưng sau đó tạm thời sẽ vẫn còn sống ít nhất miễn là tham chiếu, và nó không phải là quá dễ dàng để vượt qua điều này vô tình (tôi giả sử bạn có nghĩa là 'char const & ct = 't'; foo (ct) ; '). – Oberon

+0

Cảm ơn! Tôi không biết bạn có thể sử dụng công cụ sửa đổi 'xóa' cho các chức năng toàn cầu. – Roman

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