Нет соответствия для оператора вызова, когда std :: bind-ing a std :: function с std :: future - PullRequest
0 голосов
/ 25 мая 2020

Когда я пытаюсь преобразовать std::bind a std::future<T> в std::function<void(std::future<T>)>, я получаю компилятор, т.е. ошибку шаблона, которую я не совсем понимаю. Мне кажется, что вывод шаблона std::bind идет наперекосяк, но я также не уверен, как правильно вставить параметры шаблона вручную.

#include <iostream>
#include <functional>
#include <future>
#include <utility>
#include <exception>

int main() {
    using my_result_t = int;
    std::function<void(std::future<my_result_t>)> callback {
        [] (auto result) {
            try {
                auto result_value = result.get();
                std::cout << "Result " << result_value << "\n";
            } catch (std::exception& exception) {
                std::cerr << exception.what() << "\n";
                throw;
            }
        }
    };
    std::promise<my_result_t> promise{};
    promise.set_exception(std::make_exception_ptr(std::runtime_error("Foo")));
    std::future<my_result_t> future = promise.get_future();
    auto f = std::bind(callback, std::move(future));
    f();
}
24:7: error: no match for call to ‘(std::_Bind<std::function<void(std::future<int>)>(std::future<int>)>) ()’
  24 |     f();

Полный текст ошибки от g cc:

[ 50%] Building CXX object CMakeFiles/untitled5.dir/main.cpp.o
/home/markus/CLionProjects/untitled5/main.cpp: In function ‘int main()’:
/home/markus/CLionProjects/untitled5/main.cpp:24:7: error: no match for call to ‘(std::_Bind<std::function<void(std::future<int>)>(std::future<int>)>) ()’
   24 |     f();
      |       ^
In file included from /home/markus/CLionProjects/untitled5/main.cpp:2:
/usr/include/c++/9.3.0/functional:480:2: note: candidate: ‘template<class ... _Args, class _Result> _Result std::_Bind<_Functor(_Bound_args ...)>::operator()(_Args&& ...) [with _Args = {_Args ...}; _Result = _Result; _Functor = std::function<void(std::future<int>)>; _Bound_args = {std::future<int>}]’
  480 |  operator()(_Args&&... __args)
      |  ^~~~~~~~
/usr/include/c++/9.3.0/functional:480:2: note:   template argument deduction/substitution failed:
/usr/include/c++/9.3.0/functional: In substitution of ‘template<class _Functor, class ... _Bound_args> template<class _Fn, class _CallArgs, class ... _BArgs> using _Res_type_impl = typename std::result_of<_Fn&(std::_Bind<_Functor(_Bound_args ...)>::_Mu_type<_BArgs, _CallArgs>&& ...)>::type [with _Fn = std::function<void(std::future<int>)>; _CallArgs = std::tuple<>; _BArgs = {std::future<int>}; _Functor = std::function<void(std::future<int>)>; _Bound_args = {std::future<int>}]’:
/usr/include/c++/9.3.0/functional:447:8:   required by substitution of ‘template<class _Functor, class ... _Bound_args> template<class _CallArgs> using _Res_type = std::_Bind<_Functor(_Bound_args ...)>::_Res_type_impl<_Functor, _CallArgs, _Bound_args ...> [with _CallArgs = std::tuple<>; _Functor = std::function<void(std::future<int>)>; _Bound_args = {std::future<int>}]’
/usr/include/c++/9.3.0/functional:478:9:   required from here
/usr/include/c++/9.3.0/functional:443:8: error: no type named ‘type’ in ‘class std::result_of<std::function<void(std::future<int>)>&(std::future<int>&)>’
  443 |  using _Res_type_impl
      |        ^~~~~~~~~~~~~~
/usr/include/c++/9.3.0/functional:491:2: note: candidate: ‘template<class ... _Args, class _Result> _Result std::_Bind<_Functor(_Bound_args ...)>::operator()(_Args&& ...) const [with _Args = {_Args ...}; _Result = _Result; _Functor = std::function<void(std::future<int>)>; _Bound_args = {std::future<int>}]’
  491 |  operator()(_Args&&... __args) const
      |  ^~~~~~~~
/usr/include/c++/9.3.0/functional:491:2: note:   template argument deduction/substitution failed:
/usr/include/c++/9.3.0/functional: In substitution of ‘template<class _Functor, class ... _Bound_args> template<class _Fn, class _CallArgs, class ... _BArgs> using _Res_type_impl = typename std::result_of<_Fn&(std::_Bind<_Functor(_Bound_args ...)>::_Mu_type<_BArgs, _CallArgs>&& ...)>::type [with _Fn = std::add_const<std::function<void(std::future<int>)> >::type; _CallArgs = std::tuple<>; _BArgs = {std::add_const<std::future<int> >::type}; _Functor = std::function<void(std::future<int>)>; _Bound_args = {std::future<int>}]’:
/usr/include/c++/9.3.0/functional:454:8:   required by substitution of ‘template<class _Functor, class ... _Bound_args> template<class _CallArgs, template<class _CallArgs, template<class> class __cv_quals> template<class _Functor, class ... _Bound_args> template<class> class __cv_quals> using _Res_type_cv = std::_Bind<_Functor(_Bound_args ...)>::_Res_type_impl<typename __cv_quals<typename std::enable_if<(bool)((std::tuple_size<_Tuple>::value + 1)), _Functor>::type>::type, _CallArgs, typename __cv_quals<_Bound_args>::type ...> [with _CallArgs = std::tuple<>; __cv_quals = std::add_const; _Functor = std::function<void(std::future<int>)>; _Bound_args = {std::future<int>}]’
/usr/include/c++/9.3.0/functional:489:9:   required from here
/usr/include/c++/9.3.0/functional:443:8: error: no type named ‘type’ in ‘class std::result_of<const std::function<void(std::future<int>)>&(const std::future<int>&)>’
  443 |  using _Res_type_impl
      |        ^~~~~~~~~~~~~~
/usr/include/c++/9.3.0/functional:509:2: note: candidate: ‘template<class ... _Args, class _Result> _Result std::_Bind<_Functor(_Bound_args ...)>::operator()(_Args&& ...) volatile [with _Args = {_Args ...}; _Result = _Result; _Functor = std::function<void(std::future<int>)>; _Bound_args = {std::future<int>}]’
  509 |  operator()(_Args&&... __args) volatile
      |  ^~~~~~~~
/usr/include/c++/9.3.0/functional:509:2: note:   template argument deduction/substitution failed:
/usr/include/c++/9.3.0/functional: In substitution of ‘template<class _Functor, class ... _Bound_args> template<class _Fn, class _CallArgs, class ... _BArgs> using _Res_type_impl = typename std::result_of<_Fn&(std::_Bind<_Functor(_Bound_args ...)>::_Mu_type<_BArgs, _CallArgs>&& ...)>::type [with _Fn = std::add_volatile<std::function<void(std::future<int>)> >::type; _CallArgs = std::tuple<>; _BArgs = {std::add_volatile<std::future<int> >::type}; _Functor = std::function<void(std::future<int>)>; _Bound_args = {std::future<int>}]’:
/usr/include/c++/9.3.0/functional:454:8:   required by substitution of ‘template<class _Functor, class ... _Bound_args> template<class _CallArgs, template<class _CallArgs, template<class> class __cv_quals> template<class _Functor, class ... _Bound_args> template<class> class __cv_quals> using _Res_type_cv = std::_Bind<_Functor(_Bound_args ...)>::_Res_type_impl<typename __cv_quals<typename std::enable_if<(bool)((std::tuple_size<_Tuple>::value + 1)), _Functor>::type>::type, _CallArgs, typename __cv_quals<_Bound_args>::type ...> [with _CallArgs = std::tuple<>; __cv_quals = std::add_volatile; _Functor = std::function<void(std::future<int>)>; _Bound_args = {std::future<int>}]’
/usr/include/c++/9.3.0/functional:506:9:   required from here
/usr/include/c++/9.3.0/functional:443:8: error: no type named ‘type’ in ‘class std::result_of<volatile std::function<void(std::future<int>)>&(volatile std::future<int>&)>’
  443 |  using _Res_type_impl
      |        ^~~~~~~~~~~~~~
/usr/include/c++/9.3.0/functional:521:2: note: candidate: ‘template<class ... _Args, class _Result> _Result std::_Bind<_Functor(_Bound_args ...)>::operator()(_Args&& ...) const volatile [with _Args = {_Args ...}; _Result = _Result; _Functor = std::function<void(std::future<int>)>; _Bound_args = {std::future<int>}]’
  521 |  operator()(_Args&&... __args) const volatile
      |  ^~~~~~~~
/usr/include/c++/9.3.0/functional:521:2: note:   template argument deduction/substitution failed:
/usr/include/c++/9.3.0/functional: In substitution of ‘template<class _Functor, class ... _Bound_args> template<class _Fn, class _CallArgs, class ... _BArgs> using _Res_type_impl = typename std::result_of<_Fn&(std::_Bind<_Functor(_Bound_args ...)>::_Mu_type<_BArgs, _CallArgs>&& ...)>::type [with _Fn = std::add_cv<std::function<void(std::future<int>)> >::type; _CallArgs = std::tuple<>; _BArgs = {std::add_cv<std::future<int> >::type}; _Functor = std::function<void(std::future<int>)>; _Bound_args = {std::future<int>}]’:
/usr/include/c++/9.3.0/functional:454:8:   required by substitution of ‘template<class _Functor, class ... _Bound_args> template<class _CallArgs, template<class _CallArgs, template<class> class __cv_quals> template<class _Functor, class ... _Bound_args> template<class> class __cv_quals> using _Res_type_cv = std::_Bind<_Functor(_Bound_args ...)>::_Res_type_impl<typename __cv_quals<typename std::enable_if<(bool)((std::tuple_size<_Tuple>::value + 1)), _Functor>::type>::type, _CallArgs, typename __cv_quals<_Bound_args>::type ...> [with _CallArgs = std::tuple<>; __cv_quals = std::add_cv; _Functor = std::function<void(std::future<int>)>; _Bound_args = {std::future<int>}]’
/usr/include/c++/9.3.0/functional:518:9:   required from here
/usr/include/c++/9.3.0/functional:443:8: error: no type named ‘type’ in ‘class std::result_of<const volatile std::function<void(std::future<int>)>&(const volatile std::future<int>&)>’
  443 |  using _Res_type_impl
      |        ^~~~~~~~~~~~~~

Ответы [ 2 ]

2 голосов
/ 25 мая 2020

std::bind хранит копии своих аргументов (здесь future), а позже использует их в качестве аргументов lvalue (с некоторыми исключениями из этого правила, которые включают ссылочные оболочки, заполнители и другие выражения привязки; не применимо здесь).

std::future не копируемо. То есть функция, которая принимает параметр по значению , типа, который не является копируемым, как ваш callback, не может быть вызван с lvalue.

В Чтобы ваш код работал, вам необходимо настроить подпись обратного вызова:

std::function<void(std::future<my_result_t>&)> callback = [] (auto& result) {
//                                        ~^~                    ~^~

Однако желательно вообще не использовать std::bind.

0 голосов
/ 26 мая 2020

Возможно, стоит упомянуть, что фактически использованное решение заключалось в замене привязки на лямбда. Что я забыл упомянуть в своем вопросе, так это то, что изменение сигнатуры обратного вызова на ссылку для меня не подходит, поскольку вызываемый f будет скопирован / перемещен в асинхронную очередь, то есть шаблон реактора, то есть boost::asio::post. Ссылка поднимет жизненные проблемы для жизни этого будущего. Я не упомянул об этом первым, так как надеюсь, что это все еще будет возможно с std::bind, но @ piotr-skotnicki прекрасно объяснил, почему это невозможно. Итак, для полноты других поисков без лишних слов:

std::future<my_result_t> future = promise.get_future();
auto f = [callback, future = std::move(future)] () mutable{
    callback(std::move(future));
};
f();
...