Giá trị đóng cửa Lambda có thể được thông qua dưới dạng tham số giá trị


18

Tôi thấy rằng lvalueviệc đóng lambda luôn có thể được truyền dưới dạng rvaluetham số hàm.

Xem trình diễn đơn giản sau đây.

#include <iostream>
#include <functional>

using namespace std;

void foo(std::function<void()>&& t)
{
}

int main()
{
    // Case 1: passing a `lvalue` closure
    auto fn1 = []{};
    foo(fn1);                          // works

    // Case 2: passing a `lvalue` function object
    std::function<void()> fn2 = []{};
    foo(fn2);                          // compile error

    return 0;
}

Trường hợp 2 là hành vi tiêu chuẩn (tôi chỉ sử dụng một std::functionmục đích trình diễn, nhưng bất kỳ loại nào khác cũng sẽ hành xử tương tự).

Làm thế nào và tại sao trường hợp 1 hoạt động? Trạng thái fn1đóng sau khi hàm trả về là gì?


5
Tôi đoán đó là bởi vì fn1được ngầm chuyển đổi sang một std::functiontrong foo(fn1). Chức năng tạm thời sau đó là một giá trị.
eike

@RichardCritten Tôi thực sự không chắc chắn, vì vậy tôi đã không đăng câu trả lời. Tôi nghĩ bây giờ không cần một cái khác.
eike

1
@eike np Tôi thường cảm thấy như vậy, và yup nhiều câu trả lời.
Richard Critten

2
@Sumudu Người hỏi câu hỏi đã đánh lừa bạn vì họ không biết họ đang cố hỏi gì. Điều họ muốn hỏi là: "Tại sao không std::functionthể suy luận các mẫu đối số được suy ra từ lambda". Chương trình của bạn không cố gắng suy ra các đối số mẫu của std::function, vì vậy không có vấn đề gì với việc chuyển đổi ngầm định.
eerorika

1
Tiêu đề của câu hỏi bạn liên kết là một chút sai lệch. std::functioncó một hàm tạo không rõ ràng chấp nhận các bao đóng lambda, do đó có chuyển đổi ngầm định. Nhưng trong trường hợp của câu hỏi được liên kết, việc khởi tạo mẫu std::functionkhông thể được suy ra từ loại lambda. (Ví dụ std::function<void()>có thể được xây dựng từ [](){return 5;}mặc dù nó có loại trả về không trống.
eike

Câu trả lời:


8

Làm thế nào và tại sao trường hợp 1 hoạt động?

Gọi foođòi hỏi một thể hiện của std::function<void()>nó liên kết với một tham chiếu giá trị . std::function<void()>có thể được xây dựng từ bất kỳ đối tượng có thể gọi nào tương thích với void()chữ ký.

Thứ nhất, một std::function<void()>đối tượng tạm thời được xây dựng từ []{}. Hàm tạo được sử dụng là # 5 ở đây , sao chép bao đóng vào std::functionthể hiện:

template< class F >
function( F f );

Khởi tạo mục tiêu với std::move(f). Nếu flà một con trỏ null để hoạt động hoặc con trỏ null cho thành viên, *thissẽ trống sau cuộc gọi.

Sau đó, functioncá thể tạm thời bị ràng buộc với tham chiếu giá trị.


Trạng thái đóng fn1 sau khi hàm trả về là gì?

Giống như trước đây, bởi vì nó đã được sao chép vào một std::functionthể hiện. Việc đóng cửa ban đầu không bị ảnh hưởng.


8

Một lambda không phải là một std::function. Các tài liệu tham khảo không liên kết trực tiếp .

Trường hợp 1 hoạt động vì lambdas có thể chuyển đổi thành std::functions. Điều này có nghĩa là tạm thời std::functionđược vật chất hóa bằng cách sao chép fn1 . Nói tạm thời có thể được liên kết với một tham chiếu giá trị, và do đó, đối số phù hợp với tham số.

Và việc sao chép cũng là lý do tại sao fn1hoàn toàn không bị ảnh hưởng bởi bất cứ điều gì xảy ra foo.


5

Trạng thái đóng fn1 sau khi hàm trả về là gì?

fn1 là không quốc tịch, vì nó không chụp được gì.

Làm thế nào và tại sao trường hợp 1 hoạt động?

Nó hoạt động vì đối số có kiểu khác với loại được tham chiếu giá trị. Bởi vì có một loại khác nhau, chuyển đổi ngầm được xem xét. Vì lambda có thể gọi được cho các đối số của điều này std::function, nên nó hoàn toàn có thể chuyển đổi sang nó thông qua hàm tạo chuyển đổi mẫu của std::function. Kết quả của việc chuyển đổi là một giá trị và do đó có thể được liên kết với tham chiếu giá trị.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.