นิพจน์แลมบ์ดาที่จับได้สามารถใช้เป็นตัวชี้ฟังก์ชั่นได้
มันยุ่งยากเพราะการแสดงออกแลมบ์ดาไม่ใช่ฟังก์ชั่นที่ง่าย จริง ๆ แล้วมันเป็นวัตถุที่มีตัวดำเนินการ ()
เมื่อคุณมีความคิดสร้างสรรค์คุณสามารถใช้สิ่งนี้! ลองนึกถึงคลาส "ฟังก์ชัน" ในรูปแบบของ std :: function หากคุณบันทึกวัตถุคุณยังสามารถใช้ตัวชี้ฟังก์ชั่น
ในการใช้ตัวชี้ฟังก์ชั่นคุณสามารถใช้สิ่งต่อไปนี้:
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;
ในการสร้างคลาสที่สามารถเริ่มทำงานได้เหมือน "std :: function" อันดับแรกคุณต้องมีคลาส / struct กว่าสามารถเก็บวัตถุและตัวชี้ฟังก์ชันได้ นอกจากนี้คุณต้องมีโอเปอเรเตอร์ () เพื่อดำเนินการ:
// 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...);
}
};
ด้วยวิธีนี้คุณสามารถเรียกใช้ lambdas ที่จับได้และไม่จับได้เช่นเดียวกับที่คุณใช้:
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;
}
รหัสนี้ใช้ได้กับ VS2015
อัพเดท 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;
}