C ++ 1y从std :: bind到std :: function没有可行的转换 [英] C++1y no viable conversion from std::bind to std::function

查看:1599
本文介绍了C ++ 1y从std :: bind到std :: function没有可行的转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图将一个转发函数存储到 std :: function 中。如果我使用 std :: bind ,我得到错误消息像没有可行的转换从... 。如果我使用lambda,它编译好了。



这里是示例代码

  #include< functional> 

template< typename Handler> void func1(int a,Handler&& amp; handler){}
template< typename Handler> void func2(Handler&&
// this line compile fine
std :: function< void()> funcA = [handler = std :: move(handler)](){func1(1,std :: move(handler)); };
//这行得到编译错误
std :: function< void()> funcB = std :: bind(func1< Handler>,1,std :: move(handler));
}

int main()
{
func2(& main); //这只是一个示例,我在实际代码中使用functor作为参数
}

同时尝试 g ++ --std = c ++ 1y (v4.9.0)和 clang ++ --std = c ++ 1y (v3.4.1) / p>

编辑:clang ++错误讯息

  main.cpp:8:28 :错误:从'typename _Bind_helper< __ is_socketlike< void(*)(int,int(*& *&&;)()),int,int(*)()> :: type' ; :: type)>')to 
'std :: function< void()>'
std :: function< void()> funcB = std :: bind(& func1< Handler>,1,std :: move(handler));
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~
main.cpp:14:5:注意:在实例化函数模板专用化中'func2< int(*)()>'request here
func2(& main);
^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.9.0/../../../../include/c++/4.9 .0 / functional:2181:7:note:候选构造函数不可行:no
从'typename _Bind_helper <__ is_socketlike (*)()> :: type'(aka'_Bind< __ func_type(typename decay< ; int> :: type,typename decay< int(*)()> :: type)>')到'nullptr_t'用于第一个参数
function(nullptr_t)noexcept
^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.9.0/../../../../include/c++/4.9.0/functional:2192:7 :注意:候选构造函数不可行:no
从'typename _Bind_helper< __ is_socketlike< void(*)(int,int(*& (int,int(*&&)()),int,int
(*)()> :: type'(aka'_Bind< __ func_type(typename decay< int& decay< int(*)()> :: type)>')to'const std :: function< void() &'
第一个参数
函数(const function& __x);
^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.9.0/../../../../include/c++/4.9 .0 / functional:2201:7:注意:候选构造函数不可行:no
从'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
第一个参数
函数(函数& __x):_Function_base()
^
/usr/bin/../lib64/gcc/x86_64 -unknown-linux-gnu / 4.9.0 /../../../../ include / c ++ / 4.9.0 / functional:2226:2:注意:候选模板忽略:
替换失败[与_Functor = std :: _ Bind< void(*(int,int(*)()))(int,int(*&)())>]:没有匹配的函数调用
type'std :: _ Bind< void(*(int,int(*)()))(int,int(*&&)())>'
function(_Functor);
^
生成了1个错误。


解决方案

介绍



std :: bind 将尝试使用 lvalue-reference 调用 func1< Handler> 但您的实例化 func1 会使其只接受右值






< h3>说明

在这里,我们已将您的测试用例减少到最低限度,以显示发生了什么,下面的代码段格式不正确,并解释为什么是

  #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 int&&& )。



std :: move(123)会将 move-construct 的值存储在由 std :: bind 创建的对象中,当 std :: bind 稍后调用存储的函数时,所有参数都以 TiD cv& 即。



此行为是由标准强制执行的( [func.bind.bind] p10 中所述,您可以使用jtc1 / sc22 / wg21 / docs / papers / 2013 / n3797.pdf> n3797 )。






通过将上述错误的代码段更改为以下内容,因为 foobar< int> 现在接受 lvalue-reference ;适合通过 std :: bind 返回的函数对象绑定到传递给我们的函数的
$ b

  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
}


I am trying to store a forward function into std::function. If I use std::bind, I get error message like no viable conversion from .... If I use lambda, it compile okay.

Here is sample code

#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
}

Trying both g++ --std=c++1y (v4.9.0) and clang++ --std=c++1y (v3.4.1) yield the same result

edit: clang++ error message

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.

解决方案

INTRODUCTION

std::bind will try to call func1<Handler> with an lvalue-reference, but your instantiation of func1 will make it only accept rvalues.


EXPLANATION

Here we have reduced your testcase to the bare minimum to show what is going on, the snippet below is ill-formed and an explanation will follow to why that is.

#include <functional>

template<class T>
void foobar (T&& val);

int main() {
  std::function<void()> f = std::bind (&foobar<int>, std::move (123));
}

In the above we will instantiate foobar with T = int, which makes the type of argument val to be an rvalue-reference to int (int&&).

std::move(123) will move-construct our value to be stored inside the object created by std::bind, but the Standard says that when std::bind later invokes the stored function, all arguments are passed as TiD cv &; ie. as lvalues.

This behavior is mandated by the Standard (n3797), as stated in section [func.bind.bind]p10.


By changing the previous ill-formed snippet into the following, no error will be raised, since foobar<int> now accepts an lvalue-reference; suitable to be bound to the lvalue passed to our function by the function-object returned by std::bind.

  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
}

这篇关于C ++ 1y从std :: bind到std :: function没有可行的转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆