Các biểu thức Lambda, thậm chí là các biểu thức được bắt giữ, có thể được xử lý như một con trỏ hàm (con trỏ tới hàm thành viên).
Đó là khó khăn vì một biểu thức lambda không phải là một chức năng đơn giản. Nó thực sự là một đối tượng với một toán tử ().
Khi bạn sáng tạo, bạn có thể sử dụng điều này! Hãy nghĩ về một lớp "hàm" theo kiểu std :: function. Nếu bạn lưu đối tượng, bạn cũng có thể sử dụng con trỏ hàm.
Để sử dụng con trỏ hàm, bạn có thể sử dụng như sau:
int first = 5;
auto lambda = [=](int x, int z) {
return x + z + first;
};
int(decltype(lambda)::*ptr)(int, int)const = &decltype(lambda)::operator();
std::cout << "test = " << (lambda.*ptr)(2, 3) << std::endl;
Để xây dựng một lớp có thể bắt đầu hoạt động như một "std :: function", trước tiên bạn cần một lớp / struct hơn là có thể lưu trữ đối tượng và con trỏ hàm. Ngoài ra, bạn cần một toán tử () để thực thi nó:
// OT => Object Type
// RT => Return Type
// A ... => Arguments
template<typename OT, typename RT, typename ... A>
struct lambda_expression {
OT _object;
RT(OT::*_function)(A...)const;
lambda_expression(const OT & object)
: _object(object), _function(&decltype(_object)::operator()) {}
RT operator() (A ... args) const {
return (_object.*_function)(args...);
}
};
Với điều này, giờ đây bạn có thể chạy lambdas bị bắt, không bị bắt, giống như bạn đang sử dụng bản gốc:
auto capture_lambda() {
int first = 5;
auto lambda = [=](int x, int z) {
return x + z + first;
};
return lambda_expression<decltype(lambda), int, int, int>(lambda);
}
auto noncapture_lambda() {
auto lambda = [](int x, int z) {
return x + z;
};
return lambda_expression<decltype(lambda), int, int, int>(lambda);
}
void refcapture_lambda() {
int test;
auto lambda = [&](int x, int z) {
test = x + z;
};
lambda_expression<decltype(lambda), void, int, int>f(lambda);
f(2, 3);
std::cout << "test value = " << test << std::endl;
}
int main(int argc, char **argv) {
auto f_capture = capture_lambda();
auto f_noncapture = noncapture_lambda();
std::cout << "main test = " << f_capture(2, 3) << std::endl;
std::cout << "main test = " << f_noncapture(2, 3) << std::endl;
refcapture_lambda();
system("PAUSE");
return 0;
}
Mã này hoạt động với VS2015
Cập nhật 04/07/17:
template <typename CT, typename ... A> struct function
: public function<decltype(&CT::operator())(A...)> {};
template <typename C> struct function<C> {
private:
C mObject;
public:
function(const C & obj)
: mObject(obj) {}
template<typename... Args> typename
std::result_of<C(Args...)>::type operator()(Args... a) {
return this->mObject.operator()(a...);
}
template<typename... Args> typename
std::result_of<const C(Args...)>::type operator()(Args... a) const {
return this->mObject.operator()(a...);
}
};
namespace make {
template<typename C> auto function(const C & obj) {
return ::function<C>(obj);
}
}
int main(int argc, char ** argv) {
auto func = make::function([](int y, int x) { return x*y; });
std::cout << func(2, 4) << std::endl;
system("PAUSE");
return 0;
}