当 std::bind-ing std::function 与 std::future 时,呼叫运营商不匹配
No match for call operator when std::bind-ing a std::function with a std::future
当我尝试 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();
来自 gcc 的完整错误文本:
[ 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
| ^~~~~~~~~~~~~~
std::bind
存储其参数的副本(这里是移动构造的 future
),然后将它们用作左值参数(该规则有一些例外情况,包括引用包装器、占位符和其他绑定表达式;none 适用于此处)。
std::future
不可复制构造。也就是说,接受参数 by-value 的函数,其类型不可复制构造,就像您的 callback
一样,不能使用左值调用。
为了使您的代码正常工作,您需要调整回调的签名:
std::function<void(std::future<my_result_t>&)> callback = [] (auto& result) {
// ~^~ ~^~
不过,最好不要使用 std::bind
。
可能值得一提的是,实际使用的解决方案是用 lambda 替换绑定。我在问题中忘记提到的是,将回调的签名更改为引用对我来说不是一个合适的选择,因为 f 可调用对象将 copied/moved 放入异步队列,即反应器模式,即 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();
当我尝试 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();
来自 gcc 的完整错误文本:
[ 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
| ^~~~~~~~~~~~~~
std::bind
存储其参数的副本(这里是移动构造的 future
),然后将它们用作左值参数(该规则有一些例外情况,包括引用包装器、占位符和其他绑定表达式;none 适用于此处)。
std::future
不可复制构造。也就是说,接受参数 by-value 的函数,其类型不可复制构造,就像您的 callback
一样,不能使用左值调用。
为了使您的代码正常工作,您需要调整回调的签名:
std::function<void(std::future<my_result_t>&)> callback = [] (auto& result) {
// ~^~ ~^~
不过,最好不要使用 std::bind
。
可能值得一提的是,实际使用的解决方案是用 lambda 替换绑定。我在问题中忘记提到的是,将回调的签名更改为引用对我来说不是一个合适的选择,因为 f 可调用对象将 copied/moved 放入异步队列,即反应器模式,即 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();