#include "Tutorial.h" void FunctionTutorial() { /// .Function /// U++ `Function` is quite similar to `std::function` - it is a function wrapper that can /// store/copy/invoke any callable target. There are two important differences. /// First, invoking empty `Function` is NOP, if `Function` has return type `T`, it returns /// `T()`. Second, `Function` allows effective chaining of callable targets using /// `operator<<`, if `Function` has return type, the return type of last callable appended /// is used. /// Usually, the callable target is C++11 lambda: Function fn = [](int n) { LOG("Called A"); return 3 * n; }; LOG("About to call function"); int n = fn(7); DUMP(n); /// If you chain another lambda into `Function`, all are called, but the last one's return /// value is used: fn << [](int n) { LOG("Called B"); return n * n; }; LOG("About to call combined function"); n = fn(7); DUMP(n); /// Invoking empty lambda does nothing and returns default constructed return value. This /// is quite useful for GUI classes, which have a lot of output events represented by /// `Function` which are often unassigned to any action. fn.Clear(); LOG("About to call empty function"); n = fn(7); DUMP(n); /// While using `Function` with lambda expression is the most common, you can use any /// target that has corresponding `operator()` defined: struct Functor { int operator()(int x) { LOG("Called Foo"); return x % 2; } }; fn = Functor(); LOG("About to call Functor"); n = fn(7); DUMP(n); /// As `Function` with `void` and `bool` return types are the most frequently used, U++ /// defines template aliases `Event`: Event<> ev = [] { LOG("Event invoked"); }; ev(); /// and `Gate`: Gate gt = [](int x) { LOG("Gate invoked with " << x); return x < 10; }; bool b = gt(9); DUMP(b); b = gt(10); DUMP(b); /// Using lambda to define calls to methods with more parameters can be verbose and /// error-prone. The issue can be simplified by using `THISFN` macro: struct Foo { void Test(int a, const String& b) { LOG("Foo::Test " << a << ", " << b); } typedef Foo CLASSNAME; // required for THISFN void Do() { Event fn; fn = [=](int a, const String& b) { Test(a, b); }; fn(1, "using lambda"); fn = THISFN(Test); // this is functionally equivalent, but less verbose fn(2, "using THISFN"); } }; Foo f; f.Do(); /// }