]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/local_function/doc/examples.qbk
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / local_function / doc / examples.qbk
CommitLineData
7c673cae
FG
1
2[/ Copyright (C) 2009-2012 Lorenzo Caminiti ]
3[/ Distributed under the Boost Software License, Version 1.0 ]
4[/ (see accompanying file LICENSE_1_0.txt or a copy at ]
5[/ http://www.boost.org/LICENSE_1_0.txt) ]
6[/ Home at http://www.boost.org/libs/local_function ]
7
8[section Examples]
9
10This section lists some examples that use this library.
11
12[section GCC Lambdas (without C++11)]
13
14Combing local functions with the non-standard [@http://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html statement expression] extension of the GCC compiler, it is possible to implement lambda functions for GCC compilers even without __CXX11__ support.
15
16[warning
17This code only works on compilers that support GCC statement expression extension or that support __CXX11_lambda_functions__.
18]
19
20For example (see also [@../../example/gcc_lambda.cpp =gcc_lambda.cpp=] and [@../../example/gcc_cxx11_lambda.cpp =gcc_cxx11_lambda.cpp=]):
21
22[table
23 [ [With Local Functions (GCC only)] [C++11 Lambdas] ]
24 [ [[gcc_lambda]] [[gcc_cxx11_lambda]] ]
25]
26
27The GCC lambda function macros are implemented using local functions (see also [@../../example/gcc_lambda.hpp =gcc_lambda.hpp=]):
28
29[gcc_lambda_macro]
30[gcc_lambda_end_macro]
31
32This is possible because GCC statement expressions allow to use declaration statements within expressions and therefore to declare a local function within an expression.
33The macros automatically detect if the compiler supports __CXX11_lambda_functions__ in which case the implementation uses native lambdas instead of local functions in GCC statement expressions.
34However, __CXX11_lambda_functions__ do not support constant binding so it is best to only use `const bind variable` (same as `=variable` for __CXX11_lambda_functions__) and `bind& variable` (same as `&variable` for __CXX11_lambda_functions__') because these have the exact same semantic between the local function and the native lambda implementations.
35Furthermore, local functions allow to bind data members directly while __CXX11_lambda_functions__ require to access data members via binding the object `this`.
36Unfortunately, the short-hand binds `&` and `=` of __CXX11_lambda_functions__ (which automatically bind all variables in scope either by reference or value) are not supported by these GCC lambda function macros because they are not supported by local functions.
37Finally, the result type `return `[^['result-type]] is optional and it is assumed `void` when it is not specified (same as with __CXX11_lambda_functions__).
38
39[endsect]
40
41[section Constant Blocks]
42
43It is possible to use local functions to check assertions between variables that are made constant within the asserted expressions.
44This is advantageous because assertions are not supposed to change the state of the program and ideally the compiler will not compile assertions that modify variables.
45
46For example, consider the following assertion where by mistake we programmed `operator=` instead of `operator==`:
47
48 int x = 1, y = 2;
49 assert(x = y); // Mistakenly `=` instead of `==`.
50
51Ideally this code will not compile instead this example not only compiles but the assertion even passes the run-time check and no error is generated at all.
52The __N1613__ paper introduces the concept of a /const-block/ which could be used to wrap the assertion above and catch the programming error at compile-time.
53Similarly, the following code will generate a compile-time error when `operator=` is mistakenly used instead of `operator==` because both `x` and `y` are made constants (using local functions) within the block of code performing the assertion (see also [@../../example/const_block_error.cpp =const_block_error.cpp=]):
54
55[table
56 [ [With Local Functions] [N1613 Const-Blocks] ]
57 [ [[const_block]] [``
58 int x = 1, y = 2;
59 const { // Constant block.
60 assert(x = y); // Compiler error.
61 }
62 ``] ]
63]
64
65The constant block macros are implemented using local functions (see also [@../../example/const_block.hpp =const_block.hpp=]):
66
67[const_block_macro]
68[const_block_end_macro]
69
70The constant block macros are implemented using a local function which binds by constant reference `const bind&` all the specified variables (so the variables are constant within the code block but they do not need to be `CopyConstructible` and no extra copy is performed).
71The local function executes the `assert` instruction in its body and it is called immediately after it is defined.
72More in general, constant blocks can be used to evaluate any instruction (not just assertions) within a block were all specified variables are constant.
73
74Unfortunately, constant blocks cannot be implemented with __CXX11_lambda_functions__ because these do not support constant binding.
75Variables bound by value using __CXX11_lambda_functions__ (`variable`, `=variable`, and `=`) are constant but they are required to be `CopyConstructible` and they introduce potentially expensive copy operations.
76[footnote
77Ideally, __CXX11_lambda_functions__ would allow to bind variables also using `const& variable` (constant reference) and `const&` (all variables by constant reference).
78]
79Of course it is always possible to introduce extra constant variables and bind these variables to the __CXX11_lambda_functions__ but the constant block code will then have to manage the declaration and initialization of these extra variables plus it will have to use the extra variable names instead of the original variable names:
80
81[const_block_cxx11_lambda]
82
83In many cases the use of an extra constant variable `const_x` can be acceptable but in other cases it might be preferable to maintain the same variable name `x` within the function body.
84
85[endsect]
86
87[section Scope Exits]
88
89Scope exits allow to execute arbitrary code at the exit of the enclosing scope and they are provided by the __Boost_ScopeExit__ library.
90
91For curiosity, here we show how to re-implement scope exits using local functions.
92One small advantage of scope exits that use local functions is that they support constant binding.
93__Boost_ScopeExit__ does not directly support constant binding (however, it is always possible to introduce an extra `const` local variable, assign it to the value to bind, and then bind the `const` variable so to effectively have constant binding with __Boost_ScopeExit__ as well).
94
95[note
96In general, the authors recommend to use __Boost_ScopeExit__ instead of the code listed by this example whenever possible (because __Boost_ScopeExit__ is a library deliberately designed to support the scope exit construct).
97]
98
99The following example binds `p` by constant reference so this variable cannot be modified within the scope exit body but it is not copied and it will present the value it has at the exit of the enclosing scope and not at the scope exit declaration (see also [@../../example/scope_exit.cpp =scope_exit.cpp=]):
100
101[table
102 [ [With Local Functions] [Boost.ScopeExit] ]
103 [ [[scope_exit]] [``
104 person& p = persons_.back();
105 person::evolution_t checkpoint = p.evolution_;
106
107 BOOST_SCOPE_EXIT(checkpoint, &p, this_) { // Or extra variable `const_p`.
108 if (checkpoint == p.evolution_) this_->persons_.pop_back();
109 } BOOST_SCOPE_EXIT_END
110 ``] ]
111]
112
113The scope exit macros are implemented by passing a local function when constructing an object of the following class (see also [@../../example/scope_exit.hpp =scope_exit.hpp=]):
114
115[scope_exit_class]
116[scope_exit_macro]
117[scope_exit_end_macro]
118
119A local variable within the enclosing scope is used to hold the object so the destructor will be invoked at the exit of the enclosing scope and it will in turn call the local function executing the scope exit instructions.
120The scope exit local function has no parameter and `void` result type but it supports binding and constant binding.
121
122[endsect]
123
124[section Boost.Phoenix Functions]
125
126Local functions can be used to create __Boost_Phoenix__ functions.
127For example (see also [@../../example/phoenix_factorial_local.cpp =phoenix_factorial_local.cpp=] and [@../../example/phoenix_factorial.cpp =phoenix_factorial.cpp=]):
128
129[table
130 [ [Local Functions] [Global Functor] ]
131 [ [[phoenix_factorial_local]] [[phoenix_factorial]] ]
132]
133
134This is presented here mainly as a curiosity because __Boost_Phoenix__ functions created from local functions have the important limitation that they cannot be polymorphic.
135[footnote
136*Rationale.*
137Local functions can only be monomorphic because they are implemented using local classes and local classes cannot be templates in C++ (not even in __CXX11__).
138]
139Therefore, in many cases creating the __Boost_Phoenix__ function from global functors (possibly with the help of __Boost_Phoenix__ adaptor macros) might be a more useful.
140
141[endsect]
142
143[section Closures]
144
145The following are examples of [@http://en.wikipedia.org/wiki/Closure_(computer_science) closures] that illustrate how to return local functions to the calling scope (note how extra care is taken in order to ensure that all bound variables remain valid at the calling scope):
146
147[table
148 [ [Files] ]
149 [ [[@../../test/return_inc.cpp =return_inc.cpp=]] ]
150 [ [[@../../test/return_this.cpp =return_this.cpp=]] ]
151 [ [[@../../test/return_setget.cpp =return_setget.cpp=]] ]
152 [ [[@../../test/return_derivative.cpp =return_derivative.cpp=]] ]
153]
154
155[endsect]
156
157[section GCC Nested Functions]
158
159The GCC C compiler supports local functions as a non-standard extension under the name of [@http://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html nested functions].
160Note that nested functions are exclusively a C extension of the GCC compiler (they are not supported for C++ not even by the GCC compiler, and they are not part of any C or C++ standard, nor they are supported by other compilers like MSVC).
161
162The following examples are taken form the GCC nested function documentation and programmed using local functions:
163
164[table
165 [ [Files] ]
166 [ [[@../../example/gcc_square.cpp =gcc_square.cpp=]] ]
167 [ [[@../../example/gcc_access.cpp =gcc_access.cpp=]] ]
168 [ [[@../../example/gcc_store.cpp =gcc_store.cpp=]] ]
169]
170
171[endsect]
172
173[section N-Papers]
174
175The following examples are taken from different C++ "N-papers" and programmed using local functions:
176
177[table
178 [ [Files] [Notes] ]
179 [ [[@../../example/n2550_find_if.cpp =n2550_find_if.cpp=]] [
180This example is adapted from __N2550__ (__CXX11_lambda_functions__): It passes a local function to the STL algorithm `std::find_if`.
181 ] ]
182 [ [[@../../example/n2529_this.cpp =n2529_this.cpp=]] [
183This example is adapted from __N2529__ (__CXX11_lambda_functions__): It binds the object in scope `this` to a local function.
184 ] ]
185]
186
187[endsect]
188
189[endsect]
190