ultimatepp/tutorial/CoreTutorial/Function.cpp
cxl 6c22e727de New Core Tutorial
git-svn-id: svn://ultimatepp.org/upp/trunk@10538 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2016-12-12 10:08:40 +00:00

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();
///
}