2010-07-01 38 views
8

Trong C++ 0x, tôi tự hỏi kiểu gõ là hàm lambda. Cụ thể:Loại hàm lambda là gì?

#include<iostream> 

type1 foo(int x){ 
return [x](int y)->int{return x * y;}; 
} 

int main(){ 

std::cout<<foo(3)(4);//would output 12 

type2 bar = foo(5); 
std::cout<<bar(6);//would output 30 
return 0; 
} 

Tôi cần thay thế loại1/type2 bằng cách nào để làm việc ở trên? Hy vọng rằng bạn có thể thấy những gì tôi đang cố gắng để thực hiện, vì vậy ngay cả khi điều này là không thể bởi một sự thay thế trực tiếp của type1 và type2, có lẽ bạn có thể hướng dẫn tôi đi đúng hướng.

Nói cách khác:

  • Làm thế nào tôi có thể nhận được một hàm trả về một chức năng ẩn danh?
  • Làm cách nào để gán một hàm ẩn danh cho một biến?

Cảm ơn!

Chỉnh sửa: Tôi đang biên soạn với visual studio 2010

Trả lời

14

Bạn không bao giờ có thể biết loại chức năng lambda bởi vì những gì hợp lý xảy ra là trình biên dịch tạo ra một lớp (địa phương) với chức năng điều hành cuộc gọi quá tải và một đóng cửa từ vựng được đại diện bởi các thành viên dữ liệu của lớp đó (địa phương). Đây là những gì hợp lý xảy ra đối với một hàm lambda như:

auto foo = [](int x, int y) { return x + y; }; 

Trình biên dịch một cách logic thực hiện điều này:

struct CompilerGeneratedName { void operator()(int x, int y) const { return x + y; } }; 
CompilerGeneratedName foo; 

Kể từ khi trình biên dịch tạo ra một lớp (địa phương), nó tạo ra một tên và do đó bạn có thể không bao giờ viết một cách rõ ràng loại, bạn chỉ có thể suy ra loại từ các loại khấu trừ của các đối số hàm mẫu hoặc sử dụng auto/decltype.

Ngoài ra đóng C++ 0x được phân bổ tĩnh nên bạn không thể trả lại một cách an toàn nguyên bản đóng C++ 0x.

Vẫn có một vài cách bạn có thể đạt được điều này, đầu tiên là linh hoạt hơn và hỗ trợ các hàm lambda nắm bắt phạm vi từ vựng. Sử dụng std :: function, nếu bạn có hàm lambda không capture bất cứ thứ gì từ phạm vi bên ngoài thì bạn có thể sử dụng con trỏ hàm nhưng chuyển đổi này là nhiều hơn để làm việc với mã cũ hơn bất cứ thứ gì.

Vì vậy, về cơ bản những gì bạn muốn là thế này:

std::function< int (int) > foo(int x) 
{ 
    return [x](int y)->int{return x * y;}; 
} 

Lý do tại sao tôi tiếp tục nói một cách logic, là bởi vì đây là cách thúc đẩy :: lambda loại công trình ban đầu (mặc dù C++ 03 không cho phép các lớp địa phương được sử dụng trong các đối số hàm mẫu) và nơi mà ý tưởng thêm hàm lambda bắt nguồn từ nhưng vì đây là một tính năng ngôn ngữ giờ đây các nhà cung cấp trình biên dịch có thể thực hiện nó theo các cách khác nhau và hiệu quả hơn như khi chụp tất cả môi trường. chỉ có thể chuyển một con trỏ tới ngăn xếp cuộc gọi thay vì theo cách hợp lý trong khi vẫn duy trì chế độ xem logic.

+0

Cảm ơn, +1. Những gì bạn có nghĩa là bởi "nếu bạn lambda chức năng không phải là chụp bất cứ điều gì từ phạm vi bên ngoài sau đó bạn có thể sử dụng con trỏ chức năng."? Nó không phải là x? – Cam

+0

@incrediman có ví dụ của bạn là chụp vì vậy bạn không thể sử dụng con trỏ hàm, chỉ các hàm lambda không có trạng thái có thể được chuyển đổi thành con trỏ hàm. –

+0

@snk_kid: Ồ. Tôi thực sự chỉ đọc sai những gì bạn đã viết, nó làm cho cảm giác hoàn hảo cách nó là :) – Cam

6

Từ Wikipedia:

chức năng Lambda là đối tượng chức năng của một loại thực hiện phụ thuộc; tên của loại này chỉ có sẵn cho trình biên dịch. Nếu người dùng muốn lấy hàm lambda làm tham số, loại phải là loại mẫu hoặc phải tạo một số std::function để nắm bắt giá trị lambda.

VC10 biên dịch này

//Beware, brain-compiled code ahead! 
#include<iostream> 
#include<functional> 

std::function<int(int)> foo(int x) 
{ 
    return [x](int y)->int{return x * y;}; 
} 

int main(){ 

    std::cout<<foo(3)(4) << '\n'; 

    auto bar = foo(5); 
    std::cout<<bar(6) << '\n'; 

    return 0; 
} 

và in

 
12 
30 
+0

Điều này hoạt động hoàn hảo, cảm ơn! Bất kỳ ý tưởng gì 'std :: function' nào để làm điều này có thể? – Cam

+0

std :: function does template ma thuật, tương tự như std :: bind1st nào, ngoại trừ std :: function là dễ dàng hơn nhiều để sử dụng :-). Nó dựa trên khung công tác boost :: function, bạn có thể xem tại đây http://www.boost.org/doc/libs/1_43_0/doc/html/function/tutorial.html#id866455. Cuối cùng, std :: function đang tạo một lớp mới (sử dụng các mẫu). Lớp mới này đang sử dụng phép đúc ngầm để biến hàm lambda thành lớp mới. – Dragontamer5788