3

I want to defer the execution of a packaged task in a loop.

class ILoop { public: virtual void Deffer(std::function<void()>&& task) = 0; void Deffer(std::function<void()>& task) = delete; static void set_loop(ILoop*); static ILoop& loop(); private: static ILoop* loop_; }; template <typename T> struct LoopExecutor { std::future<T> Commit(std::function<T()>&& task) { std::packaged_task<T()> wrapper([t = std::move(task)] { return t(); }); std::future<T> future = wrapper.get_future(); ILoop::loop().Deffer([wrapper = std::move(wrapper)] { wrapper(); }); return future; } }; 

when I try to compile this

auto t = executor.Commit([] { return 100; }); 

I have compilation error:

[1/2] Building CXX object unit_tests/CMakeFiles/reduct_tests.dir/reduct/async/awaiters_test.cc.o FAILED: unit_tests/CMakeFiles/reduct_tests.dir/reduct/async/awaiters_test.cc.o /usr/bin/g++-11 -I/home/atimin/.conan/data/fmt/8.0.1/_/_/package/20da98908a15523bbe9f086a5c57a4bde424a9c0/include -I/home/atimin/.conan/data/uwebsockets/20.8.0/_/_/package/c84c7dca9672f88b95bafb2f5754a22669d1bbe5/include -I/home/atimin/.conan/data/uwebsockets/20.8.0/_/_/package/c84c7dca9672f88b95bafb2f5754a22669d1bbe5/include/uWebSockets -I/home/atimin/.conan/data/nlohmann_json/3.9.1/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include -I/home/atimin/.conan/data/gtest/1.11.0/_/_/package/63868df56b76903d4ad40ecbd5b2e8238cee50c9/include -I/home/atimin/.conan/data/catch2/2.13.7/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include -I/home/atimin/.conan/data/zlib/1.2.11/_/_/package/be27726f9885116da1158027505be62e913cd585/include -I/home/atimin/.conan/data/usockets/0.8.1/_/_/package/f3766c5a18b2feee4dc2c3a94335008aaaea2543/include -I/home/atimin/Projects/flipback/reduct-storage/src -I/home/atimin/Projects/flipback/reduct-storage/cmake-build-debug-gcc11 -I/home/atimin/Projects/flipback/reduct-storage/unit_tests -g -DLIBUS_NO_SSL -std=gnu++20 -MD -MT unit_tests/CMakeFiles/reduct_tests.dir/reduct/async/awaiters_test.cc.o -MF unit_tests/CMakeFiles/reduct_tests.dir/reduct/async/awaiters_test.cc.o.d -o unit_tests/CMakeFiles/reduct_tests.dir/reduct/async/awaiters_test.cc.o -c /home/atimin/Projects/flipback/reduct-storage/unit_tests/reduct/async/awaiters_test.cc In file included from /home/atimin/Projects/flipback/reduct-storage/src/reduct/async/awaiters.h:10, from /home/atimin/Projects/flipback/reduct-storage/unit_tests/reduct/async/awaiters_test.cc:3: /home/atimin/Projects/flipback/reduct-storage/src/reduct/async/executors.h: In instantiation of ‘std::future<_Res> reduct::async::LoopExecutor<T>::Commit(std::function<T()>&&) [with T = int]’: /home/atimin/Projects/flipback/reduct-storage/src/reduct/async/awaiters.h:40:68: required from ‘reduct::async::Run<T, Executor>::Run(std::function<T()>&&) [with T = int; Executor = reduct::async::LoopExecutor<int>]’ /home/atimin/Projects/flipback/reduct-storage/unit_tests/reduct/async/awaiters_test.cc:52:92: required from here /home/atimin/Projects/flipback/reduct-storage/src/reduct/async/executors.h:19:66: error: no match for call to ‘(const std::packaged_task<int()>) ()’ 19 | ILoop::loop().Deffer([wrapper = std::move(wrapper)] { wrapper(); }); | ~~~~~~~^~ In file included from /home/atimin/Projects/flipback/reduct-storage/src/reduct/async/awaiters.h:8, from /home/atimin/Projects/flipback/reduct-storage/unit_tests/reduct/async/awaiters_test.cc:3: /usr/include/c++/11/future:1577:7: note: candidate: ‘void std::packaged_task<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) [with _Res = int; _ArgTypes = {}]’ (near match) 1577 | operator()(_ArgTypes... __args) | ^~~~~~~~ /usr/include/c++/11/future:1577:7: note: passing ‘const std::packaged_task<int()>*’ as ‘this’ argument discards qualifiers In file included from /usr/include/c++/11/future:47, from /home/atimin/Projects/flipback/reduct-storage/src/reduct/async/awaiters.h:8, from /home/atimin/Projects/flipback/reduct-storage/unit_tests/reduct/async/awaiters_test.cc:3: /usr/include/c++/11/bits/std_function.h:414:9: error: ‘std::function<_Res(_ArgTypes ...)>::function(_Functor) [with _Functor = reduct::async::LoopExecutor<int>::Commit(std::function<int()>&&)::<lambda()>; <template-parameter-2-2> = void; <template-parameter-2-3> = void; _Res = void; _ArgTypes = {}]’, declared using local type ‘reduct::async::LoopExecutor<int>::Commit(std::function<int()>&&)::<lambda()>’, is used but never defined [-fpermissive] 414 | function(_Functor __f) 

Actually, even a simpler code (no Defer function) is also not working:

 auto t = [w = std::move(wrapper)] { w(); }; t(); 

On the other hand, it is ok:

 std::thread t(std::move(wrapper)); 

I use GCC 11.2.

3
  • You should read syntax for lambda. [](){} declares a lambda. You forgot to write () in your declaration. Commented Dec 29, 2021 at 13:14
  • 1
    @ALX23z The () for an empty parameter list are optional in a lambda. Commented Dec 29, 2021 at 13:16
  • @user17732522 it is ok. I found it in the standard. I think it is the purpose of std::packaged_task to move it into some loop or thread to execute in parallel but be able to get the result in the main thread. Commented Dec 29, 2021 at 13:38

1 Answer 1

3

By default a lambda's call operator is const-qualified.

Inside the lambda's body the this pointer to the lambda is therefore also const-qualified and so is the member wrapper. std::packaged_task does not have a const-qualified operator(), so it cannot be called.

You can make the lambda's operator() non-const-qualified by adding the mutable keyword:

[wrapper = std::move(wrapper)]()mutable{ wrapper(); } 

Note that currently the syntax for a lambda with a specifier does require the empty parameter list to be given as ().


However, you have a bigger issue: Storing a std::packaged_task inside the lambda makes the lambda non-copyable. But std::function requires the stored type to be copyable. You cannot use it for this use case, see also How to create an std::function from a move-capturing lambda expression?

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks, you're right! Only one question more, how can I declare the mutable lambda explicitly. My Deffer method expects immutable lambda - void Deffer(std::function<void()>&& task) and it is not compiling now.
Unfortunately not, so you can't compile: std::function<void()> f = []() mutable {}; But with auto ofc, it is working. My problem is that i have an interface and I don't know so far the proper signature. But it may be another topic.
@flipback I see now what the issue is. I updated the answer. Unfortunately your approach will not work.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.