2016-01-19 22 views
6

Hãy xem xét các đoạn mã sau:std :: ràng buộc và tài liệu tham khảo rvalue

class Widget{ 
}; 

int main(){ 
Widget w; 
auto lambda = bind([](Widget&& ref){ return; }, std::move(w)); 

return 0; 
} 

và nó gây ra lỗi

no match for call to ‘(std::_Bind<main()::<lambda(Widget&&)>(Widget)>)()’ 
    lambda(); 

Và câu hỏi của tôi là: Tại sao các lỗi đã xuất hiện? Sau khi tất cả, tôi làm một diễn viên rõ ràng để tham khảo rvalue - Tôi có nghĩa là std::move(w) và tôi có đối số bằng tham chiếu rvalue - Tôi có nghĩa là Widget&& ref.

Có chuyện gì?

Hơn nữa các hoạt động của mã dưới đây, những gì làm cho tôi lo lắng hơn:

class Widget{ 
}; 

int main(){ 
Widget w; 
auto lambda = bind([](Widget& ref){ return; }, std::move(w)); 

return 0; 
} 

Trả lời

7

Nó có thể trở thành rõ ràng hơn nếu bạn viết xuống những gì std::bind sơ đồ thực hiện.

// C++14, you'll have to write a lot of boilerplate code for C++11 
template <typename FuncT, typename ArgT> 
auto 
bind(FuncT&& func, ArgT&& arg) 
{ 
    return 
    [ 
     f = std::forward<FuncT>(func), 
     a = std::forward<ArgT>(arg) 
    ]() mutable { return f(a); }; // NB: a is an lvalue here 
} 

Vì bạn có thể gọi cho đối tượng chức năng std::bind mang đến cho bạn nhiều lần, nó không thể “sử dụng” các lập luận bắt vì vậy nó sẽ được thông qua như là một tài liệu tham khảo giá trị trái. Thực tế là bạn tự vượt qua bind một giá trị chỉ có nghĩa là không có bản sao nào được thực hiện trên dòng nơi a được khởi tạo.

Nếu bạn cố gắng biên dịch ví dụ của mình với sơ đồ bind được hiển thị ở trên, bạn cũng sẽ nhận được thông báo lỗi hữu ích hơn từ trình biên dịch của mình.

main.cxx: In instantiation of ‘bind(FuncT&&, ArgT&&)::<lambda()> mutable [with FuncT = main()::<lambda(Widget&&)>; ArgT = Widget]’: 
main.cxx:10:33: required from ‘struct bind(FuncT&&, ArgT&&) [with FuncT = main()::<lambda(Widget&&)>; ArgT = Widget]::<lambda()>’ 
main.cxx:11:31: required from ‘auto bind(FuncT&&, ArgT&&) [with FuncT = main()::<lambda(Widget&&)>; ArgT = Widget]’ 
main.cxx:18:59: required from here 
main.cxx:11:26: error: no match for call to ‘(main()::<lambda(Widget&&)>) (Widget&)’ 
    ]() mutable { return f(a); }; // NB: a is an lvalue here 
         ^
main.cxx:11:26: note: candidate: void (*)(Widget&&) <conversion> 
main.cxx:11:26: note: conversion of argument 2 would be ill-formed: 
main.cxx:11:26: error: cannot bind ‘Widget’ lvalue to ‘Widget&&’ 
main.cxx:18:33: note: candidate: main()::<lambda(Widget&&)> <near match> 
    auto lambda = bind([](Widget&&){ return; }, std::move(w)); 
           ^
main.cxx:18:33: note: conversion of argument 1 would be ill-formed: 
main.cxx:11:26: error: cannot bind ‘Widget’ lvalue to ‘Widget&&’ 
    ]() mutable { return f(a); }; // NB: a is an lvalue here 
1

Để làm cho nó làm việc bạn cần phải viết nó như thế này:

#include <functional> 
#include <iostream> 

class Widget{}; 

int main() 
{ 
    Widget a; 
    auto lf = [](Widget&& par){ }; 

    auto f = std::bind 
    (
     lf, 
     std::bind 
     (
      std::move<Widget&>, a 
     ) 
    ); 
    f(); 
    return 0; 
} 

trình biên dịch của tôi là gcc version 4.9.2 20141101 (Red Hat 4.9.2-1) (GCC)

+1

dụ của bạn không hoạt động. Hãy thử gọi f(); – Gilgamesz

+0

Làm thế nào bạn nhận ra rằng ví dụ này không hoạt động? Tôi biên dịch thành công nó với trình biên dịch của tôi. Trình biên dịch nào bạn sử dụng? – zaratustra

+0

http://ideone.com/tl8tc3 – Gilgamesz

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