2012-02-08 35 views
40

Tôi muốn tạo một lớp mà khách hàng có thể lưu trữ một biểu thức lambda như []() -> void {} dưới dạng một trường của lớp, nhưng tôi không thể tìm ra cách làm như vậy. One answer suggested using decltype, mà tôi đã thử không thành công. Đây là ideone source link. Dưới đây là nguồn gốc và kết quả:Làm cách nào để lưu trữ một biểu thức lambda dưới dạng một trường của một lớp trong C++ 11?

#include <cstdio> 
auto voidLambda = []()->void{}; 

class MyClass { 
public: 
    decltype(voidLambda) t; 
    MyClass(decltype(voidLambda) t) { 
     this->t = t; 
    } 
}; 

int main() { 
    MyClass([] { 
     printf("hi"); 
    }); 
} 

Kết quả:

prog.cpp: In constructor 'MyClass::MyClass(<lambda()>)': 
prog.cpp:3:79: error: no matching function for call to '<lambda()>::__lambda0()' 
prog.cpp:2:20: note: candidates are: <lambda()>::<lambda>(const<lambda()>&) 
prog.cpp:2:20: note:     <lambda()>::<lambda>(<lambda()>&&) 
prog.cpp:3:88: error: no match for 'operator=' in '((MyClass*)this)->MyClass::t = t' 
prog.cpp: In function 'int main()': 
prog.cpp:5:27: error: no matching function for call to 'MyClass::MyClass(main()::<lambda()>)' 
prog.cpp:3:48: note: candidates are: MyClass::MyClass(<lambda()>) 
prog.cpp:3:14: note:     MyClass::MyClass(const MyClass&) 

Có ai biết làm thế nào để làm điều này?

+5

Mỗi lambda tạo ra nó là loại độc đáo riêng. Trong 'auto A = []() {}; auto B = []() {}; '' A' và 'B' không cùng loại. – bames53

+1

Thật không may 'struct A {auto x = 0; }; 'không được phép. –

Trả lời

40

Nếu bạn muốn một thành viên của lớp là biểu thức lambda, hãy cân nhắc sử dụng loại trình bao bọc std::function<> (từ tiêu đề <functional>), có thể giữ bất kỳ chức năng nào có thể gọi. Ví dụ:

std::function<int()> myFunction = []() { return 0; } 
myFunction(); // Returns 0; 

Bằng cách này, bạn không cần phải biết loại biểu thức lambda. Bạn chỉ có thể lưu trữ std::function<> loại chức năng thích hợp và hệ thống mẫu sẽ xử lý tất cả các loại cho bạn. Nói chung, bất kỳ thực thể có thể gọi nào của chữ ký thích hợp đều có thể được gán cho một std::function<>, ngay cả khi loại thực tế của functor đó là vô danh (trong trường hợp lambdas) hoặc thực sự phức tạp.

Loại bên trong mẫu std::function phải là loại chức năng tương ứng với chức năng bạn muốn lưu trữ. Vì vậy, ví dụ: để lưu trữ một hàm có hai số int và trả về khoảng trống, bạn sẽ tạo một std::function<void (int, int)>. Đối với một hàm không có tham số và trả về một số int, bạn sẽ sử dụng std::function<int()>. Trong trường hợp của bạn, vì bạn muốn một hàm không có tham số và trả về void, bạn sẽ muốn một cái gì đó như thế này:

class MyClass { 
public: 
    std::function<void()> function; 
    MyClass(std::function<void()> f) : function(f) { 
     // Handled in initializer list 
    } 
}; 

int main() { 
    MyClass([] { 
     printf("hi") 
    }) mc; // Should be just fine. 
} 

Hy vọng điều này sẽ giúp!

+0

Câu hỏi: là '-> void' thực sự cần thiết ở đây? Tôi biết mệnh đề return có thể được bỏ qua (và do đó được suy ra) trong một số trường hợp và điều này khiến tôi bắt đầu một trường hợp dễ dàng (không có 'return'). –

+0

@ MatthieuM.- Tôi thực sự không chắc chắn! Tôi đã có ấn tượng rằng bạn phải có nó, nhưng nếu tôi nhầm thì tôi rất sẵn lòng cập nhật câu trả lời này. – templatetypedef

+0

Vâng, tôi cũng đang học, vì vậy tôi đã hy vọng * bạn * sẽ biết :) –

7

Cách duy nhất tôi có thể nghĩ ra để lưu trữ một lambda trong một lớp học là sử dụng một mẫu với một helper make_ chức năng:

biểu
#include <cstdio> 
#include <utility> 

template<class Lambda> 
class MyClass { 
    Lambda _t; 
public: 
    MyClass(Lambda &&t) : _t(std::forward<Lambda>(t)) { 
     _t(); 
    } 
}; 

template<class Lambda> 
MyClass<Lambda> make_myclass(Lambda &&t) { 
    return { std::forward<Lambda>(t) }; 
} 

int main() { 
    make_myclass([] { 
     printf("hi"); 
    }); 
} 
+4

phá vỡ sự cần thiết phải xác định đối số mẫu bằng cách giới thiệu helper này 'make_myclass'. Đó là [Thành ngữ trình tạo đối tượng] (https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Object_Generator). – mucaho

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