c ++ 0x: cách thích hợp để nhận lambda dưới dạng tham số bằng tham chiếu


82

Cách đúng để xác định một hàm nhận int->inttham số lambda bằng cách tham chiếu là gì?

void f(std::function< int(int) >& lambda);

hoặc là

void f(auto& lambda);

Tôi không chắc biểu mẫu cuối cùng là cú pháp hợp pháp.

Có những cách nào khác để xác định một tham số lambda?


10
Tại sao bạn cần lambda bằng cách tham khảo? Ý bạn là const&?
deft_code

Câu trả lời:


82

Bạn không thể có một autotham số. Về cơ bản bạn có hai lựa chọn:

Tùy chọn # 1: Sử dụng std::functionnhư bạn đã hiển thị.

Tùy chọn # 2: Sử dụng tham số mẫu:

template<typename F>
void f(F &lambda) { /* ... */}

Tùy chọn số 2, trong một số trường hợp, có thể hiệu quả hơn, vì nó có thể tránh phân bổ heap tiềm năng cho đối tượng hàm lambda được nhúng, nhưng chỉ khả thi nếu fcó thể được đặt trong tiêu đề như một hàm mẫu. Nó cũng có thể làm tăng thời gian biên dịch và dấu chân I-cache, cũng như bất kỳ mẫu nào. Lưu ý rằng nó cũng có thể không có tác dụng, vì nếu đối tượng hàm lambda đủ nhỏ, nó có thể được biểu diễn nội tuyến trong std::functionđối tượng.


1
Mẫu cũng có thể cải thiện I-bộ nhớ cache dấu chân, bằng cách loại bỏ nhảy mã phi địa phương nói chung (trong trường hợp này, hãy thực hiện lambda của bạn trực tiếp, mà không cần phải nhảy qua các mục đích chung std::functionwrapper đầu tiên)
jalf

5
Trích dẫn này, "nếu đối tượng hàm lambda đủ nhỏ, nó có thể được biểu diễn nội tuyến trong std::functionđối tượng" là gây hiểu lầm. Lambdas luôn có sẵn cho nội tuyến (tất nhiên trình biên dịch có thể chọn không). std::functiontriển khai thường sử dụng tối ưu hóa đối tượng nhỏ để tránh phân bổ đống. Nếu lambda có một danh sách chụp đủ nhỏ, nó sẽ được lưu trữ trong đó std::functionmà không cần sử dụng heap. Ngoài ra, kích thước của lambda không có ý nghĩa thực sự.
deft_code

2
@bdonlan: Nhân tiện, tại sao lại có &trong đó void f(F & lambda)?
Nawaz

2
@bdonlan: Nhưng const & giả định rằng các thành viên của lambda (các giá trị bắt theo giá trị) không thể thay đổi. Đó có thể không phải là những gì người dùng muốn.
Nicol Bolas

2
@bdonlan Đã lâu rồi, nhưng việc chuyển dưới dạng tham chiếu không phải const không cho phép xây dựng lambda tạm thời trong lệnh gọi hàm. Một tham chiếu giá trị r sẽ là tốt nhất ở đây.
zennehoy

45

Tôi sẽ sử dụng templatenhư:

template<typename Functor>
void f(Functor functor)
{
   cout << functor(10) << endl;
}

int g(int x)
{
    return x * x;
}
int main() 
{
    auto lambda = [] (int x) { cout << x * 50 << endl; return x * 100; };
    f(lambda); //pass lambda
    f(g);      //pass function 
}

Đầu ra:

500
1000
100

Demo: http://www.ideone.com/EayVq


12

Tôi biết đã 7 năm, nhưng đây là một cách mà chưa ai đề cập đến:

void foo(void (*f)(int)){
    std::cout<<"foo"<<std::endl;
    f(1); // calls lambda which takes an int and returns void
}
int main(){
    foo([](int a){std::cout<<"lambda "<<a<<std::endl;});
}

Đầu ra nào:

foo
lambda 1

Không cần mẫu hoặc hàm std ::


10
điều này chỉ giới hạn đối với lambdas có thể phân rã thành con trỏ hàm (lambdas w / o nắm bắt) và cũng yêu cầu chỉ định chữ ký chính xác (tương tự như đối với std::functiontrường hợp) trong khi phiên bản mẫu không có giới hạn này.
Andriy Tylychko

1

void f(auto& lambda);

Nó đã đóng cửa. Những gì thực sự sẽ biên dịch là:

#include <cassert>

/*constexpr optional*/ const auto f = [](auto &&lambda)
{
  lambda();
  lambda();
};

int main()
{
  int counter = 0;
  f([&]{ ++counter; });
  assert(counter == 2);
}
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.