|  | Home | Libraries | People | FAQ | More | 
This section lists some examples that use this library.
Combing local functions with the non-standard statement expression extension of the GCC compiler, it is possible to implement lambda functions for GCC compilers even without C++11 support.
| ![[Warning]](../../../../../doc/src/images/warning.png) | Warning | 
|---|---|
| This code only works on compilers that support GCC statement expression extension or that support C++11 lambda functions. | 
        For example (see also gcc_lambda.cpp
        and gcc_cxx11_lambda.cpp):
      
| With Local Functions (GCC only) | C++11 Lambdas | 
|---|---|
| 
 int val = 2; int nums[] = {1, 2, 3}; int* end = nums + 3; int* iter = std::find_if(nums, end, GCC_LAMBDA(const bind val, int num, return bool) { return num == val; } GCC_LAMBDA_END ); 
 | 
 int val = 2; int nums[] = {1, 2, 3}; int* end = nums + 3; int* iter = std::find_if(nums, end, [val](int num) -> bool { return num == val; } ); 
 | 
        The GCC lambda function macros are implemented using local functions (see
        also gcc_lambda.hpp):
      
# define GCC_LAMBDA_(binds, params, results) \ ({ /* open statement expression (GCC extension only) */ \ BOOST_LOCAL_FUNCTION( \ BOOST_PP_LIST_ENUM(BOOST_PP_LIST_APPEND(binds, \ BOOST_PP_LIST_APPEND(params, \ BOOST_PP_IIF(BOOST_PP_LIST_IS_NIL(results), \ (return void, BOOST_PP_NIL) /* default for lambdas */ \ , \ results \ )\ ) \ )) \ )
#define GCC_LAMBDA_END_(id) \ BOOST_LOCAL_FUNCTION_NAME(BOOST_PP_CAT(gcc_lambda_, id)) \ BOOST_PP_CAT(gcc_lambda_, id); \ }) /* close statement expression (GCC extension only) */
        This is possible because GCC statement expressions allow to use declaration
        statements within expressions and therefore to declare a local function within
        an expression. The macros automatically detect if the compiler supports
        C++11
        lambda functions in which case the implementation uses native lambdas
        instead of local functions in GCC statement expressions. However, C++11
        lambda functions do not support constant binding so it is best to
        only use const bind
        variable (same as =variable
        for C++11
        lambda functions) and bind& variable
        (same as &variable
        for C++11
        lambda functions') because these have the exact same semantic between
        the local function and the native lambda implementations. Furthermore, local
        functions allow to bind data members directly while C++11
        lambda functions require to access data members via binding the object
        this. Unfortunately, the short-hand
        binds & and = of C++11
        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. Finally, the result
        type return result-type
        is optional and it is assumed void
        when it is not specified (same as with C++11
        lambda functions).
      
It is possible to use local functions to check assertions between variables that are made constant within the asserted expressions. This 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.
        For example, consider the following assertion where by mistake we programmed
        operator=
        instead of operator==:
      
int x = 1, y = 2; assert(x = y); // Mistakenly `=` instead of `==`.
        Ideally 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. The [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. Similarly, 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 const_block_error.cpp):
      
| With Local Functions | N1613 Const-Blocks | 
|---|---|
| 
 int x = 1, y = 2; CONST_BLOCK(x, y) { // Constant block. assert(x = y); // Compiler error. } CONST_BLOCK_END 
 | 
 int x = 1, y = 2; const { // Constant block. assert(x = y); // Compiler error. } 
 | 
        The constant block macros are implemented using local functions (see also
        const_block.hpp):
      
#define CONST_BLOCK_(variables) \ void BOOST_LOCAL_FUNCTION( \ BOOST_PP_IIF(BOOST_PP_LIST_IS_NIL(variables), \ void BOOST_PP_TUPLE_EAT(3) \ , \ BOOST_PP_LIST_FOR_EACH_I \ )(CONST_BLOCK_BIND_, ~, variables) \ )
#define CONST_BLOCK_END_(id) \ BOOST_LOCAL_FUNCTION_NAME(BOOST_PP_CAT(const_block_, id)) \ BOOST_PP_CAT(const_block_, id)(); /* call local function immediately */
        The 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). The local function executes the assert instruction in its body and it is
        called immediately after it is defined. More in general, constant blocks
        can be used to evaluate any instruction (not just assertions) within a block
        were all specified variables are constant.
      
        Unfortunately, constant blocks cannot be implemented with C++11
        lambda functions because these do not support constant binding. Variables
        bound by value using C++11
        lambda functions (variable,
        =variable,
        and =) are constant but they
        are required to be CopyConstructible
        and they introduce potentially expensive copy operations. [29] Of course it is always possible to introduce extra constant variables
        and bind these variables to the C++11
        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:
      
int x = 1, y = 2; const decltype(x)& const_x = x; // Constant so cannot be modified const decltype(y)& const_y = y; // and reference so no copy. [&const_x, &const_y]() { // Lambda functions (C++11 only). assert(const_x = const_y); // Unfortunately, `const_` names. }();
        In 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.
      
Scope exits allow to execute arbitrary code at the exit of the enclosing scope and they are provided by the Boost.ScopeExit library.
        For curiosity, here we show how to re-implement scope exits using local functions.
        One small advantage of scope exits that use local functions is that they
        support constant binding. 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).
      
| ![[Note]](../../../../../doc/src/images/note.png) | Note | 
|---|---|
| In 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). | 
        The 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
        scope_exit.cpp):
      
| With Local Functions | Boost.ScopeExit | 
|---|---|
| 
 person& p = persons_.back(); person::evolution_t checkpoint = p.evolution_; SCOPE_EXIT(const bind checkpoint, const bind& p, bind this_) { if (checkpoint == p.evolution_) this_->persons_.pop_back(); } SCOPE_EXIT_END 
 | 
 person& p = persons_.back(); person::evolution_t checkpoint = p.evolution_; BOOST_SCOPE_EXIT(checkpoint, &p, this_) { // Or extra variable `const_p`. if (checkpoint == p.evolution_) this_->persons_.pop_back(); } BOOST_SCOPE_EXIT_END 
 | 
        The scope exit macros are implemented by passing a local function when constructing
        an object of the following class (see also scope_exit.hpp):
      
struct scope_exit { scope_exit(boost::function<void (void)> f): f_(f) {} ~scope_exit(void) { f_(); } private: boost::function<void (void)> f_; };
# define SCOPE_EXIT(...) \ void BOOST_LOCAL_FUNCTION(__VA_ARGS__)
#define SCOPE_EXIT_END_(id) \ BOOST_LOCAL_FUNCTION_NAME(BOOST_PP_CAT(scope_exit_func_, id)) \ scope_exit BOOST_PP_CAT(scope_exit_, id)( \ BOOST_PP_CAT(scope_exit_func_, id));
        A 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.
        The scope exit local function has no parameter and void
        result type but it supports binding and constant binding.
      
        Local functions can be used to create Boost.Phoenix
        functions. For example (see also phoenix_factorial_local.cpp
        and phoenix_factorial.cpp):
      
| Local Functions | Global Functor | 
|---|---|
| 
 int main(void) { using boost::phoenix::arg_names::arg1; int BOOST_LOCAL_FUNCTION(int n) { // Unfortunately, monomorphic. return (n <= 0) ? 1 : n * factorial_impl(n - 1); } BOOST_LOCAL_FUNCTION_NAME(recursive factorial_impl) boost::phoenix::function< boost::function<int (int)> > factorial(factorial_impl); // Phoenix function from local function. int i = 4; BOOST_TEST(factorial(i)() == 24); // Call. BOOST_TEST(factorial(arg1)(i) == 24); // Lazy call. return boost::report_errors(); } 
 | 
 struct factorial_impl { // Phoenix function from global functor. template<typename Sig> struct result; template<typename This, typename Arg> struct result<This (Arg)> : result<This (Arg const&)> {}; template<typename This, typename Arg> struct result<This (Arg&)> { typedef Arg type; }; template<typename Arg> // Polymorphic. Arg operator()(Arg n) const { return (n <= 0) ? 1 : n * (*this)(n - 1); } }; int main(void) { using boost::phoenix::arg_names::arg1; boost::phoenix::function<factorial_impl> factorial; int i = 4; BOOST_TEST(factorial(i)() == 24); // Call. BOOST_TEST(factorial(arg1)(i) == 24); // Lazy call. return boost::report_errors(); } 
 | 
This is presented here mainly as a curiosity because Boost.Phoenix functions created from local functions have the important limitation that they cannot be polymorphic. [30] Therefore, 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.
The following are examples of 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):
The GCC C compiler supports local functions as a non-standard extension under the name of nested functions. Note 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).
The following examples are taken form the GCC nested function documentation and programmed using local functions:
The following examples are taken from different C++ "N-papers" and programmed using local functions:
| Files | Notes | 
|---|---|
| 
                  This example is adapted from [N2550]
                  (C++11
                  lambda functions): It passes a local function to the STL
                  algorithm  | |
| 
                  This example is adapted from [N2529]
                  (C++11
                  lambda functions): It binds the object in scope  | 
[29] 
          Ideally, C++11
          lambda functions would allow to bind variables also using const& variable (constant reference) and const&
          (all variables by constant reference).