From 45a2b40caa1a1681b01fc91b36c2a8d45be3d906 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Sun, 6 Oct 2019 22:40:09 -0400 Subject: [PATCH] Replace std::bind in documentation --- include/deal.II/base/function.h | 10 ++-- include/deal.II/base/mutable_bind.h | 11 +++-- include/deal.II/base/parallel.h | 30 ++++++------ include/deal.II/base/parameter_handler.h | 2 +- include/deal.II/base/work_stream.h | 10 ++-- include/deal.II/distributed/tria.h | 34 +++++++------- include/deal.II/grid/filtered_iterator.h | 4 +- include/deal.II/grid/tria.h | 6 ++- include/deal.II/lac/solver.h | 34 +++++++------- include/deal.II/matrix_free/matrix_free.h | 6 ++- include/deal.II/numerics/time_dependent.h | 56 ++++++++++++----------- 11 files changed, 109 insertions(+), 94 deletions(-) diff --git a/include/deal.II/base/function.h b/include/deal.II/base/function.h index 051b55c79e..205f1bcf0d 100644 --- a/include/deal.II/base/function.h +++ b/include/deal.II/base/function.h @@ -649,10 +649,10 @@ protected: * * 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 * class Norm : public Function @@ -702,7 +702,7 @@ protected: * or we could write it like so: * @code * ScalarFunctionFromFunctionObject my_distance_object( - * std::bind(&Point::distance, q, std::placeholders::_1)); + * [&q](const Point &p){return q.distance(p);}); * @endcode * The savings in work to write this are apparent. * diff --git a/include/deal.II/base/mutable_bind.h b/include/deal.II/base/mutable_bind.h index 8abbaf6d1a..f2f888763c 100644 --- a/include/deal.II/base/mutable_bind.h +++ b/include/deal.II/base/mutable_bind.h @@ -54,7 +54,7 @@ namespace Utilities * 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 @@ -67,10 +67,11 @@ namespace Utilities * const Point<2> p(1, 2); * * Utilities::MutableBind 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"); diff --git a/include/deal.II/base/parallel.h b/include/deal.II/base/parallel.h index f68b6a9db4..07fc76b72c 100644 --- a/include/deal.II/base/parallel.h +++ b/include/deal.II/base/parallel.h @@ -398,11 +398,11 @@ namespace parallel * { * 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); * } * @@ -418,14 +418,11 @@ namespace parallel * } * @endcode * - * Note how we use the std::bind function to convert + * Note how we use the lambda function to convert * mat_vec_on_subranges from a function that takes 5 arguments - * to one taking 2 by binding the remaining arguments (the modifiers - * std::ref and std::cref 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 * mat_vec_on_subranges on the entire range @@ -641,10 +638,11 @@ namespace parallel * std::sqrt * (parallel::accumulate_from_subranges * (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); * } * diff --git a/include/deal.II/base/parameter_handler.h b/include/deal.II/base/parameter_handler.h index 8cf22ea24c..fdaaf0d61f 100644 --- a/include/deal.II/base/parameter_handler.h +++ b/include/deal.II/base/parameter_handler.h @@ -346,7 +346,7 @@ class MultipleParameterLoop; * 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 * lambda * function that has the form * @code diff --git a/include/deal.II/base/work_stream.h b/include/deal.II/base/work_stream.h index 1c7470f6c8..bb51de6613 100644 --- a/include/deal.II/base/work_stream.h +++ b/include/deal.II/base/work_stream.h @@ -910,7 +910,8 @@ namespace WorkStream * * 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 ScratchData and CopyData need to * have a working copy constructor. ScratchData is only used in the @@ -951,8 +952,11 @@ namespace WorkStream * * 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 diff --git a/include/deal.II/distributed/tria.h b/include/deal.II/distributed/tria.h index 8376b466f6..04fbe84ab9 100644 --- a/include/deal.II/distributed/tria.h +++ b/include/deal.II/distributed/tria.h @@ -170,18 +170,20 @@ namespace parallel * ... create the coarse mesh ... * * coarse_grid.signals.post_refinement.connect( - * std::bind (&set_boundary_ids, std::ref(coarse_grid))); + * [&coarse_grid](){ + * set_boundary_ids(coarse_grid); + * }); * } * @endcode * - * What the call to std::bind 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 connect 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 set_boundary_ids with the reference to the - * coarse grid as argument. + * call set_boundary_ids 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 @@ -210,17 +212,17 @@ namespace parallel * ... create the coarse mesh ... * * coarse_grid.signals.post_refinement.connect( - * std::bind (&MyGeometry::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, set_boundary_ids - * implicitly takes a pointer or reference to the object it belongs to as - * first argument. std::bind 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 set_boundary_ids 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 + * set_boundary_ids with a reference to the triangulation to + * work on. Note that * because the create_coarse_mesh function is declared as * const, it is necessary that the * set_boundary_ids function is also declared diff --git a/include/deal.II/grid/filtered_iterator.h b/include/deal.II/grid/filtered_iterator.h index 14d0aa54e1..4f8dd04e4b 100644 --- a/include/deal.II/grid/filtered_iterator.h +++ b/include/deal.II/grid/filtered_iterator.h @@ -387,11 +387,11 @@ namespace IteratorFilters * @endcode * then * @code - * std::bind (&level_equal_to, std::placeholders::_1, 3) + * [](const BIterator& c){ return level_equal_to(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: diff --git a/include/deal.II/grid/tria.h b/include/deal.II/grid/tria.h index fadbd3127b..cc4c38c478 100644 --- a/include/deal.II/grid/tria.h +++ b/include/deal.II/grid/tria.h @@ -1118,8 +1118,10 @@ namespace internal * // 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::invalidate_previous_cell, - * std::ref (*this))); + * [this]() + * { + * this->invalidate_previous_cell(); + * }); * } * else * previous_cell = current_cell; diff --git a/include/deal.II/lac/solver.h b/include/deal.II/lac/solver.h index 438959d236..89447402d5 100644 --- a/include/deal.II/lac/solver.h +++ b/include/deal.II/lac/solver.h @@ -206,18 +206,18 @@ class Vector; * In the language of signals, the functions called are called slots * 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 - * this argument has been bound using the - * std::bind 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 + * this 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. @@ -226,7 +226,8 @@ class Vector; * 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 @@ -283,16 +284,17 @@ class Vector; * 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 *current_iterate){ + * this->write_intermediate_solution( + * iteration, check_value, current_iterate); + * }); * solver.solve (system_matrix, solution, system_rhs, * PreconditionIdentity()); * } * @endcode - * The use of std::bind 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 this * pointer, to a function that only takes three arguments, by fixing the * implicit this argument of the function to the diff --git a/include/deal.II/matrix_free/matrix_free.h b/include/deal.II/matrix_free/matrix_free.h index eec8213bea..276fa7d21a 100644 --- a/include/deal.II/matrix_free/matrix_free.h +++ b/include/deal.II/matrix_free/matrix_free.h @@ -741,7 +741,8 @@ public: /** * 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). * @@ -1054,7 +1055,8 @@ public: * member functions of class @p CLASS with the signature operation * (const MatrixFree &, OutVector &, InVector &, * std::pair&)const. 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). * diff --git a/include/deal.II/numerics/time_dependent.h b/include/deal.II/numerics/time_dependent.h index 61c9a1289f..b5f9867fa6 100644 --- a/include/deal.II/numerics/time_dependent.h +++ b/include/deal.II/numerics/time_dependent.h @@ -252,12 +252,12 @@ class Triangulation; * 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 @@ -276,23 +276,23 @@ class Triangulation; * 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 - * C++ 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::init_for_refinement, - * std::placeholders::_1), - * std::bind(&TimeStepBase_Wave::refine_grid, - * std::placeholders::_1, - * TimeStepBase_Tria::RefinementData ( - * top_threshold, bottom_threshold)), - * TimeDependent::TimeSteppingData (0,1), - * TimeDependent::forward); + * do_loop([](TimeStepBase_Tria *const time_step) + * { time_step->init_for_refinement(); }, + * [=](TimeStepBase_Wave *const time_step) + * { + * time_step->solve_primal_problem( + * TimeStepBase_Tria::RefinementData ( + * top_threshold, bottom_threshold))); + * }, + * TimeDependent::TimeSteppingData (0,1), + * TimeDependent::forward); * @endcode * TimeStepBase_Wave::refine_grid is a function taking an argument, unlike * all the other functions used above within the loops. However, in this special @@ -535,10 +535,15 @@ public: * 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 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);. + * 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 @@ -549,10 +554,9 @@ public: * the TimeStepBase class. * * Instead of using the above form, you can equally well use - * std::bind(&X::unary_function, std::placeholders::_1, args...) - * which - * lets the @p do_loop function call the given function with the specified - * parameters. + * [args...](X *const x){x->unary_function(args...);} + * which lets the @p do_loop function call the given function with the + * specified parameters. */ template void -- 2.39.5