From 28c7f05ac6dd8bed50239c3e5cc9d63657649f32 Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Tue, 8 Mar 2016 20:08:32 -0600 Subject: [PATCH] Implement a C++11 conforming way to pass lambdas etc to new_task(). --- doc/news/changes.h | 14 ++++- include/deal.II/base/thread_management.h | 72 +++++++++++++++++++++++- 2 files changed, 82 insertions(+), 4 deletions(-) diff --git a/doc/news/changes.h b/doc/news/changes.h index 54bc77f646..e7a756978a 100644 --- a/doc/news/changes.h +++ b/doc/news/changes.h @@ -68,12 +68,12 @@ inconvenience this causes.

General

    -
  1. New: added another scaling factor to Kelly error estimator, namely h_K. +
  2. New: Added another scaling factor to Kelly error estimator, namely h_K.
    (Denis Davydov, 2016/03/05)
  3. -
  4. New: added indent target to indent all headers and source +
  5. New: Added indent target to indent all headers and source files. Now you can do make (or ninja) indent inside the build directory.
    @@ -89,7 +89,15 @@ inconvenience this causes.
      -
    1. New: When using C++11, the function filter_iterators allows to filter a +
    2. New: When using C++11, there is now a function Threads::new_task() + that can take as an argument either a lambda function, or the result + of a std::bind expression, or anything else that can be called as in a + function call. +
      + (Wolfgang Bangerth, 2016/03/07) +
    3. + +
    4. New: When using C++11, the function filter_iterators() allows to filter a range of iterators using predicates (like the ones defined in IteratorFilter).
      (Bruno Turcksin, 2016/03/04) diff --git a/include/deal.II/base/thread_management.h b/include/deal.II/base/thread_management.h index 66060f3384..588732b080 100644 --- a/include/deal.II/base/thread_management.h +++ b/include/deal.II/base/thread_management.h @@ -1,6 +1,6 @@ // --------------------------------------------------------------------- // -// Copyright (C) 2000 - 2015 by the deal.II authors +// Copyright (C) 2000 - 2016 by the deal.II authors // // This file is part of the deal.II library. // @@ -3088,6 +3088,76 @@ namespace Threads return Task(function); } + +#ifdef DEAL_II_WITH_CXX11 + + /** + * Overload of the new_task function for objects that can be called like a + * function object without arguments. In particular, this function allows + * calling Threads::new_thread() with either objects that result from using + * std::bind, or using lambda functions. For example, this function is called + * when writing code such as + * @code + * Threads::Task + * task = Threads::new_task ( [] () { + * do_this(); + * then_do_that(); + * return 42; + * }); + * @endcode + * Here, we schedule the call to the sequence of functions + * do_this() and then_do_that() on + * a separate task, by making the lambda function declared here the + * function to execute on the task. The lambda function then returns + * 42 (which is a bit pointless here, but it could of course be some + * computed number), and this is going to be the returned value you + * can later retrieve via task.return_value() once the + * task (i.e., the body of the lambda function) has completed. + * + * @note Every lambda function (or whatever else it is you pass to + * the new_task() function here, for example the result of a + * std::bind() expression) has a return type and consequently + * returns an object of this type. This type can be inferred + * using the C++11 decltype statement used in the + * declaration of this function, and it is then used as the template + * argument of the Threads::Task object returned by the current function. + * In the example above, because the lambda function returns 42 + * (which in C++ has data type int), the inferred + * type is int and the task object will have type + * Task@. In other words, it is not necessary + * to explicitly specify in user code what that return type + * of the lambda or std::bind expression will be, though it is + * possible to explicitly do so by (entirely equivalently) writing + * @code + * Threads::Task + * task = Threads::new_task ( [] () -> int { + * do_this(); + * then_do_that(); + * return 42; + * }); + * @endcode + * + * @note In practice, the lambda functions you will pass to + * new_task() will of course typically be more complicated. + * In particular, they will likely capture variables + * from the surrounding context and use them within the lambda. + * See https://en.wikipedia.org/wiki/Anonymous_function#C.2B.2B_.28since_C.2B.2B11.29 + * for more on this. + * + * @ingroup CPP11 + */ + template + inline + auto + new_task (FunctionObjectType function_object) + -> Task + { + typedef decltype(function_object()) return_type; + return Task(std_cxx11::function(function_object)); + } + +#endif + /** * Overload of the new_task function for non-member or static member * functions with no arguments. -- 2.39.5