Tôi đã làm một vài xét nghiệm sử dụng ví dụ này nhỏ hơn thể hiện hành vi tương tự bạn có:
#include <functional>
#include <iostream>
#include <string>
using std::string;
void print(string s1, string s2)
{
std::cout << s1 << s2 << '\n';
}
int main()
{
using namespace std::placeholders;
typedef std::function< void(string) > fn_t;
fn_t func = std::bind(print, _1, _1);
std::string foo("foo");
func(foo);
}
// outputs: foo
Lưu ý rằng tôi đã xác định một đối tượng chuỗi có tên là "foo" thay vì sử dụng xâu. Hành vi là như nhau, do đó, vấn đề không liên quan đến điều này.
Tôi nghĩ rằng vấn đề xuất phát từ typedef của bạn. Sự trở lại của bind
(không xác định) được đúc thành một hàm lấy string
theo giá trị, trong khi trình bao bọc được trả về bởi ràng buộc có thể lấy đối số của nó bằng cách tham chiếu rvalue và chuyển tiếp chúng hoàn toàn. Thay vì sử dụng typedef của riêng bạn, bạn nên sử dụng từ khóa auto
, để loại func
sẽ được trình biên dịch tự động suy ra. Nếu chúng ta thay đổi chính như sau, chúng tôi có được hành vi mong đợi:
int main()
{
using namespace std::placeholders;
auto func = std::bind(print, _1, _1);
std::string foo("foo");
func(foo);
}
// outputs: foofoo
giải pháp khác là để thay thế typedef của bạn để func
mất thông số của nó bằng cách tham chiếu đến const:
typedef std::function< void(string const &) > fn_t;
tôi don 't thực sự hiểu tại sao typedef khác không hoạt động ... Có lẽ chuỗi được di chuyển, như @ipc đã lưu ý, nhưng tôi không biết tại điểm nào của việc thực hiện điều này xảy ra. Tôi thậm chí không chắc chắn đây là hành vi tiêu chuẩn, vì cả hai function
và wrapper trả lại bởi bind
nên sử dụng chuyển tiếp hoàn hảo. Có lẽ GCC bao gồm một số tối ưu hóa di chuyển các đối số trình bao bọc khi chúng được truyền theo giá trị?
Sửa
tôi đã một số xét nghiệm, nó quay ra thi hành std::function
GCC của thực hiện một động thái trên lập luận của mình, trong khi sự trở lại wrapper bởi std::bind
không. Tôi vẫn không biết đây có phải là tiêu chuẩn hay không, tôi sẽ viết một câu hỏi về điều đó.
Câu hỏi rất thú vị, tôi sẽ không mong đợi một hành vi như vậy! –
Chỉ cần thêm một số sửa đổi: Đây không phải là thực sự currying. Đối số ràng buộc và currying là hai hoạt động rất giống nhau nhưng vẫn còn khác biệt, mà không nên nhầm lẫn. Currying có nghĩa là lấy một hàm nhận hàm N và biến nó thành một hàm của một đối số trả về một hàm của một đối số trả về một hàm của một đối số ... (lặp lại n Times). Bạn có thể sử dụng 'std :: bind' để thực hiện một hàm' curry' để thực hiện điều này cho bạn (với một số mở rộng). Tương tự, bạn có thể sử dụng currying để thực thi ràng buộc đối số theo cách 'std :: bind'. – LiKao
@LiKao: Thật vậy, 'bind' cho phép [một phần ứng dụng] (http://en.wikipedia.org/wiki/Partial_application), không phải currying. –