2014-11-27 21 views
15

Trong đoạn mã sau, tôi không thể vượt qua một đối tượng tạm thời như là đối số cho printAge chức năng:khởi không hợp lệ tham chiếu không const loại

struct Person { 
    int age; 
    Person(int _age): age(_age) {} 
}; 

void printAge(Person &person) { 
    cout << "Age: " << person.age << endl; 
} 

int main() { 
    Person p(50); 
    printAge(Person(50)); // fails! 
    printAge(p); 
    return 0; 
} 

Các lỗi tôi nhận được là:

error: invalid initialization of non-const reference of type ‘Person&’ from an rvalue of type ‘Person’ 

Tôi nhận ra rằng đây là điều cần làm với việc chuyển một giá trị sang một hàm mong đợi rValue ... Có cách nào để chuyển đổi lValue thành rValue bằng cách sử dụng std :: move hay gì đó không? Tôi đã cố gắng tham gia một tham số không đổi, nhưng điều đó dường như không hoạt động.

+0

Đó là cách khác xung quanh. Bạn đang chuyển một rvalue đến một hàm mong đợi một giá trị. Tham chiếu non-const lvalue không thể liên kết với rvalues, nhưng bạn có thể sử dụng tham chiếu 'const' lvalue thay thế. – juanchopanza

+4

"Tôi đã thử dùng tham số không đổi, nhưng có vẻ như nó hoạt động." Vì vậy, bạn giải quyết vấn đề, nhưng quyết định loại bỏ các giải pháp bởi vì nó có vẻ làm việc? – molbdnilo

+0

Rất tiếc, tôi đã để lại * không *! – jeffreyveon

Trả lời

14

Chỉ cần làm cho chức năng in của bạn lấy đối số của bạn bằng const&. Điều này cũng đúng về mặt logic vì nó không sửa đổi đối số của bạn.

void printAge(const Person &person) { 
    cout << "Age: " << person.age << endl; 
} 

Vấn đề thực tế là cách khác. Bạn đang chuyển một giá trị tạm thời (rvalue) cho một hàm mà dự kiến ​​một giá trị.

-2

Mã của bạn không hoạt động nếu bạn chạy trình biên dịch g ++ hoặc gcc. Bạn cần thêm const đến void printAge(const Person &person). Tuy nhiên, trong Visual Studio nó sẽ hoạt động tốt. Tôi đã thử nghiệm cho VS2010 và VS2012 và trong cả hai mã sau đây hoạt động tốt.

#include<iostream> 

using namespace std; 
struct Person { 
    int age; 
    Person(int _age): age(_age) {} 
}; 

void printAge(Person &person) { 
    cout << "Age: " << person.age << endl; 
} 

int main() { 
    Person p(50); 
    printAge(Person(50)); // DOES NOT fail! 
    printAge(p); 
    return 0; 
} 
+2

Không, điều này không nên biên dịch. Đây phải là một số phần mở rộng MSVC một lần nữa. – inf

+0

Có, tôi vừa kiểm tra g ++ hoặc gcc; cả hai đều không biên dịch nó; nhưng trong VS nó rất bình thường để vượt qua một đối tượng như một đối số mặc dù nó không được xác định const; nó nên tránh mặc dù. – telcom

+1

Bạn có thể tránh nó nhưng đối với một người dùng VS nó không sao SỬ DỤNG nó. – telcom

10

Hoặc, nếu bạn có một trình biên dịch 11-compliant C++, có thể sử dụng cái gọi là phương pháp tham khảo phổ thông, trong đó, thông qua quy tắc sụp đổ tài liệu tham khảo, có thể bám vào cả hai vế trái và rvalue tham khảo:

#include <iostream> 
using namespace std; 

struct Person { 
    int age; 
    Person(int _age): age(_age) {} 
}; 

template<typename T> // can bind to both lvalue AND rvalue references 
void printAge(T&& person) { 
    cout << "Age: " << person.age << endl; 
} 

int main() { 
    Person p(50); 
    printAge(Person(50)); // works now 
    printAge(p); 
    return 0; 
} 

Hoặc, trong C++ 14,

void printAge(auto&& person) { 
    cout << "Age: " << person.age << endl; 
} 
+3

Đây không phải là những gì urefs cho. Nếu bạn muốn xem chỉ đọc của một biến, bạn chỉ cần lấy nó bằng 'const &'. – inf

+0

@ bamboon bạn có thể mở rộng về điều này không? không thực sự hiểu nhận xét của bạn. bạn đang nói rằng urefs chỉ là để chuyển tiếp hoàn hảo? urefs làm việc hoàn hảo ở đây mặc dù. Ok, đã xem nhận xét cập nhật của bạn, đồng ý. – vsoftco

+0

Vâng, về cơ bản. Trong khi tôi không nghĩ rằng nó thực sự sai, tôi nghĩ rằng đó là khủng khiếp quá phức tạp vấn đề và lý do tại sao không ai biết nữa làm thế nào để đúng cách vượt qua các biến (ví dụ: xem thảo luận của Herb Sutter tại cppcon). Edit: Ah yeah, tôi bằng cách nào đó nhấn vào quá nhanh có lần đầu tiên. – inf

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