2012-01-13 42 views
6

Tôi có ba cuộc gọi chức năng mà tôi nghĩ rằng cần được xử lý (về) như nhau, nhưng rõ ràng là không. Tôi đang cố gắng hiểu tại sao một trong ba không biên dịch (g ++ -std = C++ 0x).nhầm lẫn ràng buộc rvalue trong C++

// Minimal example to reproduce a compile bug I want to understand. 

#include <iostream> 
#include <string> 

using namespace std; 


void bar(const string &&x) { cout << "bar: " << x << endl; } 

string returns_a_string() { return string("cow"); } 

int main(int argc, char *argv[]) 
{ 
    bar(string("horse"));  // ok 
    bar(returns_a_string()); // ok 
    string aardvark = "aardvark"; 
    bar(aardvark);   // not ok, fails to compile, error in next comment 
    /* 
     rvalue-min.cpp:29:22: error: cannot bind ‘std::string {aka std::basic_string<char>}’ lvalue to ‘const string&& {aka const std::basic_string<char>&&}’ 
     rvalue-min.cpp:10:6: error: initializing argument 1 of ‘void barR(const string&&)’ 
    */ 
} 

Câu hỏi này là một chút dọc theo dòng của C++0x rvalue references - lvalues-rvalue binding, nhưng, nếu nó trả lời đó, lời xin lỗi của tôi, tôi đã không thể cất nó ra.

Điều tôi muốn là có thể gọi cho thanh chức năng của mình() với bất kỳ loại chuỗi nào và chỉ hoạt động. Đủ để xác định void barR(const string &x), nhưng tôi thực sự muốn hiểu tại sao.

Cảm ơn bạn đã giúp đỡ nhiều trong việc hiểu tại sao cuộc gọi thứ ba lại khác.

+3

Lưu ý rằng bạn không thể thực sự làm bất kỳ điều gì hữu ích với tham chiếu rvalue * constant *. Thông thường bạn muốn khai báo 'bar (std :: string &&)'. –

+0

@KerrekSB - điểm tốt – jma

Trả lời

14

Mục đích của tham số tham chiếu giá trị r là phát hiện cụ thể khi đối tượng là giá trị r. Bởi vì nếu một đối tượng là một giá trị r, thì hàm sẽ biết nó sẽ không được sử dụng nữa, vì vậy nó có thể làm bất cứ điều gì nó muốn với nó. Nếu một giá trị l có thể liên kết với một tham chiếu giá trị r, điều đó có nghĩa là phát hiện tôi đang nói đến không thực sự xảy ra.

Nếu bạn muốn chuyển giá trị l vào một trong các chức năng này, bạn cần sử dụng std::move. Truyền một đối tượng thông qua std::move đến một hàm lấy tham chiếu giá trị r giống như nói, "ở đây, lấy đối tượng này, tách nó ra, tôi không quan tâm điều gì xảy ra với nó".

Vì mục đích của bạn, câu trả lời đúng là thực hiện tham chiếu const tham số. Một giá trị r là hoàn toàn hạnh phúc bị ràng buộc với một tham chiếu const. Ngoại trừ các nhà xây dựng di chuyển, làm cho các thông số tham chiếu giá trị r là hầu như không bao giờ là điều chính xác để làm.

+0

Không câu trả lời này không đồng ý với một ví dụ trong bài viết này (Để tìm cụ thể: Ctrl + F "// Dòng 31"): http://blogs.msdn.com/b/vcblog/archive/2009/02/03 /rvalue-references-c-0x-features-in-vc10-part-2.aspx –

+0

@sftrabbit: Có, nhưng nó đồng ý với tiêu chuẩn ngôn ngữ (và cũng với GCC, từ chối mã trong bài viết đó). –

+0

Cảm ơn. Tôi đã nhận thấy sai lầm này trong bài viết trước nhưng chưa bao giờ đi vòng để kiểm tra nó. –

4

Bạn cần sử dụng std::move. Điều này hoạt động tốt:

bar(std::move(aardvark)); 
+0

Đủ công bằng, mặc dù nó áp đặt công việc cho khách hàng. Tốt để biết, mặc dù, cảm ơn. – jma

+1

@jma: khách hàng phải làm điều đó bởi vì khách hàng đang cho phép rõ ràng cho các chức năng để tách ruột ra khỏi đối tượng. (đó là lý do tại sao const là lẻ.) Bạn chỉ nên có (const std :: string & rhs) mã để có tất cả mọi thứ. –