我正在尝试将转发函数存储到std::function
中。如果我使用std::bind
,则会收到no viable conversion from ...
之类的错误消息。如果我使用lambda,它编译好了。
以下是示例代码
#include <functional>
template<typename Handler>void func1(int a, Handler&& handler) {}
template<typename Handler>void func2(Handler&& handler)
{
// this line compile fine
std::function<void ()> funcA = [handler = std::move(handler)]() { func1(1, std::move(handler)); };
// this line got compile error
std::function<void ()> funcB = std::bind(func1<Handler>, 1, std::move(handler));
}
int main()
{
func2(&main); // this just a sample, I am using functor as argument in real code
}
同时尝试 g ++ --std = c ++ 1y (v4.9.0)和 clang ++ --std = c ++ 1y (v3.4.1)相同的结果
编辑:clang ++错误消息
main.cpp:8:28: error: no viable conversion from 'typename _Bind_helper<__is_socketlike<void (*)(int, int (*&&)())>::value, void (*)(int, int
(*&&)()), int, int (*)()>::type' (aka '_Bind<__func_type (typename decay<int>::type, typename decay<int (*)()>::type)>') to
'std::function<void ()>'
std::function<void ()> funcB = std::bind(&func1<Handler>, 1, std::move(handler));
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:14:5: note: in instantiation of function template specialization 'func2<int (*)()>' requested here
func2(&main);
^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.9.0/../../../../include/c++/4.9.0/functional:2181:7: note: candidate constructor not viable: no
known conversion from 'typename _Bind_helper<__is_socketlike<void (*)(int, int (*&&)())>::value, void (*)(int, int (*&&)()), int, int
(*)()>::type' (aka '_Bind<__func_type (typename decay<int>::type, typename decay<int (*)()>::type)>') to 'nullptr_t' for 1st argument
function(nullptr_t) noexcept
^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.9.0/../../../../include/c++/4.9.0/functional:2192:7: note: candidate constructor not viable: no
known conversion from 'typename _Bind_helper<__is_socketlike<void (*)(int, int (*&&)())>::value, void (*)(int, int (*&&)()), int, int
(*)()>::type' (aka '_Bind<__func_type (typename decay<int>::type, typename decay<int (*)()>::type)>') to 'const std::function<void ()> &'
for 1st argument
function(const function& __x);
^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.9.0/../../../../include/c++/4.9.0/functional:2201:7: note: candidate constructor not viable: no
known conversion from 'typename _Bind_helper<__is_socketlike<void (*)(int, int (*&&)())>::value, void (*)(int, int (*&&)()), int, int
(*)()>::type' (aka '_Bind<__func_type (typename decay<int>::type, typename decay<int (*)()>::type)>') to 'std::function<void ()> &&' for
1st argument
function(function&& __x) : _Function_base()
^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.9.0/../../../../include/c++/4.9.0/functional:2226:2: note: candidate template ignored:
substitution failure [with _Functor = std::_Bind<void (*(int, int (*)()))(int, int (*&&)())>]: no matching function for call to object of
type 'std::_Bind<void (*(int, int (*)()))(int, int (*&&)())>'
function(_Functor);
^
1 error generated.
答案 0 :(得分:17)
std :: bind 将尝试使用 lvalue-reference 调用func1<Handler>
,但 func1 的实例化将使它只接受 rvalues 。
在这里,我们将您的测试用例减少到最低限度,以显示正在发生的事情,下面的代码片段格式错误,并解释为什么会这样。
#include <functional>
template<class T>
void foobar (T&& val);
int main() {
std::function<void()> f = std::bind (&foobar<int>, std::move (123));
}
在上面我们将使用foobar
实例化T = int
,这使得参数类型 val 成为 rvalue-reference 到< em> int (int&&
)。
std::move(123)
将 move-construct 我们的值存储在由 std :: bind 创建的对象中,但标准说当 std :: bind 稍后调用存储的函数,所有参数都传递为TiD cv &
;即。 as lvalues 。
此行为由标准(n3797)强制执行,如[func.bind.bind]p10
部分所述。
通过将以前格式错误的代码段更改为以下内容,不会引发任何错误,因为foobar<int>
现在接受左值引用;适合绑定到由 std :: bind 返回的 function-object 传递给我们函数的 lvalue 。
std::function<void()> f = std::bind (&foobar<int&>, std::move (123));
#include <functional>
#include <type_traits>
#include <iostream>
int main() {
auto is_lvalue = [](auto&& x) {
return std::is_lvalue_reference<decltype(x)> { };
};
auto check = std::bind (is_lvalue, std::move (123));
bool res = check (); // res = true
}
答案 1 :(得分:1)
简而言之:function
必须是可复制的。带有rvalue的bind
返回不可复制的对象。解决方法是使用包含上述值的shared_ptr
捕获/绑定