mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 14:16:07 -06:00
90 lines
2.5 KiB
C++
90 lines
2.5 KiB
C++
#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<int (int)> 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<int> 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<int, const String&> 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();
|
|
|
|
///
|
|
}
|