无法调用或分配具有右值引用作为参数的 std::function (Visual C++) [英] Can't invoke or assign a std::function that has an rvalue reference as an argument (Visual C++)

查看:52
本文介绍了无法调用或分配具有右值引用作为参数的 std::function (Visual C++)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

似乎 Visual C++ 的 std::function<> 不处理以 rvalue refs 作为参数的函数.任何人都可以提出解决方法吗?

Seems like Visual C++'s std::function<> doesn't handle functions with rvalue refs as arguments. Can anyone suggest a workaround?

#include <functional>
using namespace std;

class Object { };

void f(Object&&) { }
auto g = [](Object&&){ };
function<void(Object&&)> h;

int main()
{
   Object o;
   f(move(o));
   g(move(o));

   // Uncomment any one of the following lines, and we get an error from the instantiation
   // of std::function: "error C2664: You cannot bind an lvalue to an rvalue reference"

   //h(move(o));
   //h = g;
   //h = f;

   return 0;
}

这是 Visual Studio 2010.我没有使用/Za(所以它不是 这个问题).

This is Visual Studio 2010. I am not using /Za (so it is not this problem).

经过一些研究的更新:代码在 Clang 中编译,所以我很确定这是一个 Microsoft 错误.可能是这个,在 VC11 中修复:649274

Update after some research: The code compiles in Clang, so I am pretty sure it is a Microsoft bug. It might be this one, fixed in VC11: 649274

更正更新: VC11 中未修复 MS 错误.来自链接:

Correction to the update: The MS bug is not fixed in VC11. From the link:

我们的第一个机会将是 Herb Sutter 在 VC11 和 VC12 之间的带外"发布在 GoingNative 2012 会议上宣布.

our first opportunity will be the "out of band" release between VC11 and VC12 that Herb Sutter announced at the GoingNative 2012 conference.

推荐答案

我不确定您喜欢这里的解决方法.假设您无法更改函数对象的调用表达式和目标签名,您可以包装右值引用并通过 const ref 传递包装的对象(临时).本质上,调用扩展为: f( wrap(move(o)) );

I'm not sure what workaround you'd like here. Assuming you cannot change the call expression of the function object and the target signature, you can wrap the rvalue reference and pass the wrapped object (a temporary) via const ref. Essentially, the call expands to: f( wrap(move(o)) );

我怀疑完美转发有问题,因为绑定 i = bind(&f); 不起作用;因此,我引入了一个执行完美转发的中间步骤,以便将调用解析为: f( move( (Object&)wrap( move(o) ) ) );

I suspect there's a problem with perfect forwarding, because binding i = bind(&f); does not work; therefore I've introduced an intermediate step performing perfect forwarding, such that the call is resolved to: f( move( (Object&)wrap( move(o) ) ) );

#include <iostream>
#include <functional>
using namespace std;

struct Object { int m; };

// target function with fixed signature (assuming we cannot change that)
void f(Object&& p) { p.m = 42; std::cout << p.m; };

// was surprised I didn't find any method to chain functions in the StdLib
// so here's my own:
template < typename F1, typename F2, typename P1 >
auto chain2(F1 f1, F2 f2, P1&& p1)
    -> decltype( f1(f2( std::forward<P1>(p1) )) )
{
    return f1( f2( std::forward<P1>(p1) ) );
}
// a special bind version; mostly syntactic sugar
// note you can also deduce the first template parameter; would be more work
// and not necessary here
template < typename P1, typename F1, typename F2 >
auto bind_chain(F1 f1, F2 f2)
  -> decltype( std::bind( &chain2<F1,F2,P1>, f1, f2, std::placeholders::_1 ) )
{
    return std::bind( &chain2<F1,F2,P1>, f1, f2, std::placeholders::_1 );
}

// as `std::move` is overloaded, we make things a little bit simpler;
// we later will need to get a function pointer on this, that's why
// I'd like to avoid too much overloading
template < typename T >
// for a certain reason, cannot use && here --------v, clang++3.2 accepts it
typename std::remove_reference<T>::type && my_move(T& p)
{
    return std::move(p);
}

struct wrapper
{
    Object&& m;
    wrapper(Object&& p) : m(std::move(p)) {}
    operator Object&() const { return m; }
    // alternatively:
    // operator Object&&() const { return std::move(m); }
};

int main()
{
   Object o;

   // we'll need to call the functor with an const ref
   function<void(wrapper const&)> i;

   // chaining the conversion to rvalue ref with the target function
   i = bind_chain<wrapper const&>( &f, &my_move<Object> );

   i( move(o) );

   return 0;
}

这篇关于无法调用或分配具有右值引用作为参数的 std::function (Visual C++)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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