*
* The class gains additional expressive power because the argument it takes
* does not have to be a pointer to an actual function. Rather, it is a
- * function object, i.e., it can also be the result of call to std::bind (or
- * boost::bind) or some other object that can be called with a single
- * argument. For example, if you need a Function object that returns the norm
- * of a point, you could write it like so:
+ * function object, i.e., it can also be the result of a lambda function or some
+ * other object that can be called with a single argument. For
+ * example, if you need a Function object that returns the norm of a point, you
+ * could write it like so:
* @code
* template <int dim, typename RangeNumberType>
* class Norm : public Function<dim, RangeNumberType>
* or we could write it like so:
* @code
* ScalarFunctionFromFunctionObject<dim, RangeNumberType> my_distance_object(
- * std::bind(&Point<dim>::distance, q, std::placeholders::_1));
+ * [&q](const Point<dim> &p){return q.distance(p);});
* @endcode
* The savings in work to write this are apparent.
*
* The arguments are copied to the tuple, with their reference and const
* attributes removed. Only copy constructible objects are allowed as
* function arguments. If you need to keep some references around, you may
- * wrap your function into a std::bind object:
+ * wrap your function into a lambda function:
*
* @code
* void
* const Point<2> p(1, 2);
*
* Utilities::MutableBind<void, double, unsigned int> exp = {
- * std::bind(example_function,
- * std::cref(p),
- * std::placeholders::_1,
- * std::placeholders::_2),
+ * [&p](const double &d,
+ * const unsigned int i)
+ * {
+ * example_function(p, d, i);
+ * },
* {}};
*
* exp.parse_arguments("3.0 : 4");
* {
* parallel::apply_to_subranges
* (0, A.n_rows(),
- * std::bind (&mat_vec_on_subranges,
- * std::placeholders::_1, std::placeholders::_2,
- * std::cref(A),
- * std::cref(x),
- * std::ref(y)),
+ * [&](const unsigned int begin_row,
+ * const unsigned int end_row)
+ * {
+ * mat_vec_on_subranges(begin_row, end_row, A, x, y);
+ * },
* 50);
* }
*
* }
* @endcode
*
- * Note how we use the <code>std::bind</code> function to convert
+ * Note how we use the lambda function to convert
* <code>mat_vec_on_subranges</code> from a function that takes 5 arguments
- * to one taking 2 by binding the remaining arguments (the modifiers
- * <code>std::ref</code> and <code>std::cref</code> make sure
- * that the enclosed variables are actually passed by reference and constant
- * reference, rather than by value). The resulting function object requires
- * only two arguments, begin_row and end_row, with all other arguments
- * fixed.
+ * to one taking 2 by binding the remaining arguments. The resulting function
+ * object requires only two arguments, `begin_row` and `end_row`, with all
+ * other arguments fixed.
*
* The code, if in single-thread mode, will call
* <code>mat_vec_on_subranges</code> on the entire range
* std::sqrt
* (parallel::accumulate_from_subranges<double>
* (0, A.n_rows(),
- * std::bind (&mat_norm_sqr_on_subranges,
- * std::placeholders::_1, std::placeholders::_2,
- * std::cref(A),
- * std::cref(x)),
+ * [&](const unsigned int begin_row,
+ * const unsigned int end_row)
+ * {
+ * mat_vec_on_subranges(begin_row, end_row, A, x, y);
+ * },
* 50);
* }
*
* add_action() function.) Of course, in C++ one doesn't usually pass
* around the address of a function, but an action can be a function-like
* object (taking a string as argument) that results from calling
- * @p std::bind, or more conveniently, it can be a
+ * such as a
* <a href="http://en.cppreference.com/w/cpp/language/lambda">lambda
* function</a> that has the form
* @code
*
* This function that can be used for worker and copier objects that are
* either pointers to non-member functions or objects that allow to be
- * called with an operator(), for example objects created by std::bind.
+ * called with an operator(), for example objects created by lambda functions
+ * or std::bind.
*
* The two data types <tt>ScratchData</tt> and <tt>CopyData</tt> need to
* have a working copy constructor. <tt>ScratchData</tt> is only used in the
*
* This function that can be used for worker and copier objects that are
* either pointers to non-member functions or objects that allow to be
- * called with an operator(), for example objects created by std::bind. If
- * the copier is an empty function, it is ignored in the pipeline.
+ * called with an operator(), for example lambda functions
+ * or objects created by std::bind. If the copier is an empty function, it is
+ * ignored in the pipeline. (However, a lambda function with an empty body is
+ * *not* equivalent to an empty `std::function` object and will, consequently,
+ * not be ignored.
*
* The argument passed as @p end must be convertible to the same type as @p
* begin, but doesn't have to be of the same type itself. This allows to
* ... create the coarse mesh ...
*
* coarse_grid.signals.post_refinement.connect(
- * std::bind (&set_boundary_ids<dim>, std::ref(coarse_grid)));
+ * [&coarse_grid](){
+ * set_boundary_ids<dim>(coarse_grid);
+ * });
* }
* @endcode
*
- * What the call to <code>std::bind</code> does is to produce an
- * object that can be called like a function with no arguments. It does so
- * by taking the address of a function that does, in fact, take an
- * argument but permanently fix this one argument to a reference to the
- * coarse grid triangulation. After each refinement step, the
+ * The object passed as argument to <code>connect</code> is an object
+ * that can be called like a function with no arguments. It does so by
+ * wrapping a function that does, in fact, take an argument but this one
+ * argument is stored as a reference to the coarse grid triangulation when
+ * the lambda function is created. After each refinement step, the
* triangulation will then call the object so created which will in turn
- * call <code>set_boundary_ids<dim></code> with the reference to the
- * coarse grid as argument.
+ * call <code>set_boundary_ids<dim></code> with the reference to the coarse
+ * grid as argument.
*
* This approach can be generalized. In the example above, we have used a
* global function that will be called. However, sometimes it is necessary
* ... create the coarse mesh ...
*
* coarse_grid.signals.post_refinement.connect(
- * std::bind (&MyGeometry<dim>::set_boundary_ids,
- * std::cref(*this),
- * std::ref(coarse_grid)));
+ * [this, &coarse_grid]()
+ * {
+ * this->set_boundary_ids(coarse_grid);
+ * });
* }
* @endcode
- * Here, like any other member function, <code>set_boundary_ids</code>
- * implicitly takes a pointer or reference to the object it belongs to as
- * first argument. <code>std::bind</code> again creates an object that can
+ * The lambda function above again is an object that can
* be called like a global function with no arguments, and this object in
- * turn calls <code>set_boundary_ids</code> with a pointer to the current
- * object and a reference to the triangulation to work on. Note that
+ * turn calls the current object's member function
+ * <code>set_boundary_ids</code> with a reference to the triangulation to
+ * work on. Note that
* because the <code>create_coarse_mesh</code> function is declared as
* <code>const</code>, it is necessary that the
* <code>set_boundary_ids</code> function is also declared
* @endcode
* then
* @code
- * std::bind (&level_equal_to<active_cell_iterator>, std::placeholders::_1, 3)
+ * [](const BIterator& c){ return level_equal_to<active_cell_iterator>(c, 3);}
* @endcode
* is another valid predicate (here: a function that returns true if either
* the iterator is past the end or the level is equal to the second argument;
- * this second argument is bound to a fixed value using the @p std::bind
+ * this second argument is taken considered fixed when creating the lambda
* function).
*
* Finally, classes can be predicates. The following class is one:
* // triangulation that we want to be informed about mesh refinement
* previous_cell = current_cell;
* previous_cell->get_triangulation().signals.post_refinement.connect(
- * std::bind (&FEValues<dim>::invalidate_previous_cell,
- * std::ref (*this)));
+ * [this]()
+ * {
+ * this->invalidate_previous_cell();
+ * });
* }
* else
* previous_cell = current_cell;
* In the language of signals, the functions called are called <i>slots</i>
* and one can attach any number of slots to a signal. (The implementation of
* signals and slots we use here is the one from the BOOST.signals2 library.)
- * A number of details may clarify what is happening underneath: - In reality,
- * the signal object does not store pointers to functions, but function
- * objects as slots. Each slot must conform to a particular signature: here,
- * it is an object that can be called with three arguments (the number of the
- * current linear iteration, the current residual, and the current iterate;
+ * A number of details may clarify what is happening underneath:
+ * - In reality, the signal object does not store pointers to functions, but
+ * function objects as slots. Each slot must conform to a particular signature:
+ * here, it is an object that can be called with three arguments (the number of
+ * the current linear iteration, the current residual, and the current iterate;
* more specifics are discussed in the documentation of the connect()
* function). A pointer to a function with this argument list satisfies the
* requirements, but you can also pass a member function whose
- * <code>this</code> argument has been bound using the
- * <code>std::bind</code> mechanism (see the example below). - Each of
- * the slots will return a value that indicates whether the iteration should
- * continue, should stop because it has succeeded, or stop because it has
+ * <code>this</code> argument has been bound using a lambda function
+ * (see the example below).
+ * - Each of the slots will return a value that indicates whether the iteration
+ * should continue, should stop because it has succeeded, or stop because it has
* failed. The return type of slots is therefore of type SolverControl::State.
* The returned values from all of the slots will then have to be combined
* before they are returned to the iterative solver that invoked the signal.
* otherwise, if at least one slot returned SolverControl::iterate, then this
* is going to be the return value of the signal; finally, only if all slots
* return SolverControl::success will the signal's return value be
- * SolverControl::success. - It may of course be that a particular slot has
+ * SolverControl::success.
+ * - It may of course be that a particular slot has
* been connected to the signal only to observe how the solution or a specific
* part of it converges, but has no particular opinion on whether the
* iteration should continue or not. In such cases, the slot should just
* SolverControl solver_control (1000, 1e-12);
* SolverCG<> solver (solver_control);
*
- * solver.connect (std::bind (&Step3::write_intermediate_solution,
- * this,
- * std::placeholders::_1,
- * std::placeholders::_2,
- * std::placeholders::_3));
+ * solver.connect ([this](const unsigned int iteration,
+ * const double check_value,
+ * const Vector<double> *current_iterate){
+ * this->write_intermediate_solution(
+ * iteration, check_value, current_iterate);
+ * });
* solver.solve (system_matrix, solution, system_rhs,
* PreconditionIdentity());
* }
* @endcode
- * The use of <code>std::bind</code> here ensures that we convert the
+ * The use of a lambda function here ensures that we convert the
* member function with its three arguments plus the <code>this</code>
* pointer, to a function that only takes three arguments, by fixing the
* implicit <code>this</code> argument of the function to the
/**
* This is the second variant to run the loop over all cells, now providing
* a function pointer to a member function of class `CLASS`. This method
- * obviates the need to call std::bind to bind the class into the given
+ * obviates the need to define a lambda function or to call std::bind to bind
+ * the class into the given
* function in case the local function needs to access data in the class
* (i.e., it is a non-static member function).
*
* member functions of class @p CLASS with the signature <code>operation
* (const MatrixFree<dim,Number> &, OutVector &, InVector &,
* std::pair<unsigned int,unsigned int>&)const</code>. This method obviates
- * the need to call std::bind to bind the class into the given
+ * the need to define a lambda function or to call std::bind to bind
+ * the class into the given
* function in case the local function needs to access data in the class
* (i.e., it is a non-static member function).
*
* void
* TimeDependent::solve_primal_problem ()
* {
- * do_loop (std::bind(&TimeStepBase::init_for_primal_problem,
- * std::placeholders::_1),
- * std::bind(&TimeStepBase::solve_primal_problem,
- * std::placeholders::_1),
- * timestepping_data_primal,
- * forward);
+ * do_loop([](TimeStepBase *const time_step)
+ * { time_step->init_for_primal_problem(); },
+ * [](TimeStepBase *const time_step)
+ * { time_step->solve_primal_problem(); },
+ * timestepping_data_primal,
+ * forward);
* }
* @endcode
* The latter function shows rather clear how most of the loops are invoked
* look-back and the last one denotes in which direction the loop is to be
* run.
*
- * Using function pointers through the @p std::bind functions provided by the
- * <tt>C++</tt> standard library, it is possible to do neat tricks, like the
- * following, also taken from the wave program, in this case from the function
- * @p refine_grids:
+ * Using lambda functions it is possible to do neat tricks, like the
+ * following in this case from the function @p refine_grids:
* @code
* ...
* compute the thresholds for refinement
* ...
*
- * do_loop (std::bind(&TimeStepBase_Tria<dim>::init_for_refinement,
- * std::placeholders::_1),
- * std::bind(&TimeStepBase_Wave<dim>::refine_grid,
- * std::placeholders::_1,
- * TimeStepBase_Tria<dim>::RefinementData (
- * top_threshold, bottom_threshold)),
- * TimeDependent::TimeSteppingData (0,1),
- * TimeDependent::forward);
+ * do_loop([](TimeStepBase_Tria<dim> *const time_step)
+ * { time_step->init_for_refinement(); },
+ * [=](TimeStepBase_Wave<dim> *const time_step)
+ * {
+ * time_step->solve_primal_problem(
+ * TimeStepBase_Tria<dim>::RefinementData (
+ * top_threshold, bottom_threshold)));
+ * },
+ * TimeDependent::TimeSteppingData (0,1),
+ * TimeDependent::forward);
* @endcode
* TimeStepBase_Wave<dim>::refine_grid is a function taking an argument, unlike
* all the other functions used above within the loops. However, in this special
* wake_up and @p sleep functions are called.
*
* To see how this function work, note that the function @p
- * solve_primal_problem only consists of a call to <tt>do_loop
- * (std::bind(&TimeStepBase::init_for_primal_problem, std::placeholders::_1),
- * std::bind(&TimeStepBase::solve_primal_problem, std::placeholders::_1),
- * timestepping_data_primal, forward);</tt>.
+ * solve_primal_problem only consists of the following call:
+ * @code
+ * do_loop([](TimeStepBase *const time_step)
+ * { time_step->init_for_primal_problem(); },
+ * [](TimeStepBase *const time_step)
+ * { time_step->solve_primal_problem(); },
+ * timestepping_data_primal,
+ * forward);
+ * @endcode
*
* Note also, that the given class from which the two functions are taken
* needs not necessarily be TimeStepBase, but it could also be a derived
* the TimeStepBase class.
*
* Instead of using the above form, you can equally well use
- * <tt>std::bind(&X::unary_function, std::placeholders::_1, args...)</tt>
- * which
- * lets the @p do_loop function call the given function with the specified
- * parameters.
+ * <tt>[args...](X *const x){x->unary_function(args...);}</tt>
+ * which lets the @p do_loop function call the given function with the
+ * specified parameters.
*/
template <typename InitFunctionObject, typename LoopFunctionObject>
void