2016-05-08 14 views
66

xem xét mã này:Đây có phải là std :: ref behavior logic?

#include <iostream> 
#include <functional> 

int xx = 7; 

template<class T> 
void f1(T arg) 
{ 
    arg += xx; 
} 

template<class T> 
void f2(T arg) 
{ 
    arg = xx; 
} 

int main() 
{ 
    int j; 

    j=100; 
    f1(std::ref(j)); 
    std::cout << j << std::endl; 

    j=100; 
    f2(std::ref(j)); 
    std::cout << j << std::endl; 
} 

Khi thực hiện, mã này đầu ra

107 
100 

tôi dự kiến ​​sẽ có giá trị thứ hai là 7 chứ không phải 100.

tôi đang thiếu gì?

+16

Trình bao bọc tham chiếu có thể lặp lại, do đó, gán các thay đổi được tham chiếu, chứ không phải đối tượng được tham chiếu. –

+1

Câu hỏi hay! – vsoftco

Trả lời

56

Một thay đổi nhỏ để f2 cung cấp các đầu mối:

template<class T> 
void f2(T arg) 
{ 
    arg.get() = xx; 
} 

này bây giờ làm những gì bạn mong đợi.

Điều này đã xảy ra vì std::ref trả về đối tượng std::reference_wrapper<>. Toán tử gán trong đó rebinds trình bao bọc. (xem http://en.cppreference.com/w/cpp/utility/functional/reference_wrapper/operator%3D)

Nó không thực hiện chuyển nhượng cho tham chiếu được bao bọc.

Trong trường hợp f1, tất cả đang làm việc như bạn mong đợi vì một std::reference_wrapper<T> cung cấp một nhà điều hành chuyển đổi sang T&, mà sẽ liên kết với phía bên tay phải ngầm của int s ngầm operator+.

+1

Bạn có cần một công việc không? – Ramy

+0

Được rồi, cảm ơn bạn rất nhiều – Ramy

11

reference_wrapperoperator = và một hàm tạo không rõ ràng, xem documentation.

Vì vậy, ngay cả khi nó là đáng ngạc nhiên, đó là hành vi bình thường:

f2 rebinds các reference_wrapper địa phương để xx.

8

arg = xx;

Local arg nay đề cập đến (đọc như liên kết với) xx. (Và không đề cập đến j)

arg += xx;

Implicit operator T&() được áp dụng cho phù hợp với lập luận của operator += và do đó bổ sung được thực hiện trên đối tượng được gọi ví dụ j.

Vì vậy, hành vi được quan sát là chính xác.

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