2012-06-12 48 views
8

Tôi đang bắt đầu phát triển các ứng dụng bằng cách sử dụng C++ 11 lambdas và cần phải chuyển đổi một số loại thành con trỏ hàm. Đây hoạt động hoàn hảo trong GCC 4.6.0:C++ 11 lambdas đến Con trỏ Chức năng

void (* test)() = []() 
{ 
    puts("Test!"); 
}; 

test(); 

Vấn đề của tôi là khi tôi cần phải sử dụng chức năng hoặc phương pháp biến địa phương trong lambda:

const char * text = "test!"; 

void (* test)() = [&]() 
{ 
    puts(text); 
}; 

test(); 

G ++ 4.6.0 cung cấp cho các mã lỗi dàn diễn viên:

main.cpp: In function 'void init(int)': 
main.cpp:10:2: error: cannot convert 'main(int argc, char ** argv)::<lambda()>' to 'void (*)()' in initialization 

Nếu sử dụng auto, nó hoạt động ok:

const char * text = "Test!"; 

auto test = [&]() 
{ 
    puts(text); 
}; 

test(); 

Câu hỏi của tôi là: làm cách nào để tạo loại cho lambda với [&]? Trong trường hợp của tôi, tôi không thể sử dụng STL std :: function (vì chương trình của tôi không sử dụng C++ RTTI và EXCEPTIONS runtime), và nó có thực hiện đơn giản chức năng để giải quyết vấn đề này?

+8

Âm thanh như một ví dụ về [vấn đề XY] (http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). –

+3

Bạn không thể chuyển đổi một lambda chụp sang một con trỏ hàm. Giải thích những gì bạn đang cố gắng làm. –

+0

Bạn đã giải thích (một cách tồi tệ) một giải pháp đã thử, trong khi không mô tả vấn đề thực tế của bạn là gì. Vui lòng cho chúng tôi biết vấn đề thực tế của bạn là gì – thecoshman

Trả lời

8

Tôi không thể sử dụng chức năng STL std :: (vì chương trình của tôi không sử dụng C++ Thời gian chạy RTTI và EXCEPTIONS)

Sau đó, bạn có thể cần phải viết số tiền tương đương của riêng mình là std::function.

Việc triển khai loại tẩy thông thường cho std::function không cần RTTI cho hầu hết các chức năng của nó; nó hoạt động thông qua các cuộc gọi chức năng ảo thông thường. Vì vậy, viết phiên bản của riêng bạn là có thể thực hiện được.

Thật vậy, điều duy nhất trong std::function rằng cần RTTI là target_typetarget chức năng, mà không phải là chức năng hữu ích nhất trên thế giới. Bạn có thể chỉ sử dụng std::function mà không cần gọi các chức năng này, giả sử rằng việc triển khai bạn đang sử dụng không cần RTTI cho hoạt động kinh doanh thông thường của nó.

Thông thường, khi bạn tắt xử lý ngoại lệ, chương trình sẽ tắt và lỗi khi gặp phải tuyên bố throw.Và vì hầu hết các trường hợp ngoại lệ mà std::function phát ra không phải là loại thứ bạn có thể khôi phục từ (gọi số trống function, hết bộ nhớ, v.v.), bạn có thể chỉ sử dụng std::function.

8

Chỉ các lambdas không bắt giữ có thể được chuyển đổi thành con trỏ hàm. Đây là phần mở rộng của lambdas chỉ cho trường hợp cụ thể này [*]. Nói chung, lambdas là các đối tượng hàm, và bạn không thể chuyển đổi một đối tượng hàm thành một hàm.

Cách thay thế cho lambdas có trạng thái (chụp) là sử dụng std::function thay vì con trỏ hàm đơn giản.


[*]: Nếu lambda giữ trạng thái có thể được chuyển thành con trỏ hàm, trạng thái sẽ được duy trì ở đâu? (Lưu ý rằng có thể có nhiều phiên bản của lambda cụ thể này, mỗi trường hợp có trạng thái riêng cần được duy trì riêng)

+0

Vâng, nếu bạn truyền nó theo giá trị như thế này 'const int c; [c] (int i) -> int {return i * c;} 'nó sẽ tạo ra rất nhiều ý nghĩa ... –

+0

@BarnabasSzabolcs: Nó phụ thuộc, xem xét' std :: function f (int x) {const int c = x; return [c] (int i) {return i * c;}}; '. Hàm functor được trả về bởi 'f' phụ thuộc vào đối số của nó và do đó có trạng thái. Chỉ khi chụp là một biểu thức liên tục, nó có thể được tính vào một hàm đơn giản. –

+0

Hm. Tôi đồng ý, một phần. Nó vẫn có thể được rút ra, nhưng giải pháp có thể tốn kém, vì chương trình sẽ cần phải sao chép mã của hàm lambda mỗi khi thay đổi giá trị của c trong mã chức năng. (hoặc nếu không sao chép toàn bộ mã của hàm, nó cần phải lập kế hoạch nhảy, nơi nhảy có thể làm chậm mọi thứ.) –

6

Như đã được đề cập, chỉ có lambdas mà không nắm bắt được gì có thể được chuyển đổi thành con trỏ hàm.

Nếu bạn không muốn sử dụng hoặc viết một cái gì đó như std :: chức năng sau đó thay thế khác là để vượt qua như các tham số những thứ bạn sẽ chụp khác. Bạn thậm chí có thể tạo một cấu trúc để giữ chúng.

#include <iostream> 

struct captures { int x; }; 
int (*func)(captures *c) = [](captures *c){ return c->x; }; 

int main() { 
    captures c = {10}; 

    std::cout << func(&c) << '\n'; 
} 

Một cách khác là sử dụng biến toàn cục/static/thread_local/constexpr không yêu cầu chụp.

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