无法调用或分配具有右值引用作为参数的std :: function(Visual C ++)

时间:2013-04-22 19:42:20

标签: visual-c++ rvalue-reference

似乎Visual C ++的std::function<>不处理rvalue refs作为参数的函数。有人可以建议解决方法吗?

#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 problem)。

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

更新更正:VC11中未修复MS错误。从链接:

  

我们的第一个机会将是VC11和VC12之间的“带外”释放Herb Sutter   在GoingNative 2012会议上宣布。

1 个答案:

答案 0 :(得分:1)

我不确定你在这里有什么变通方法。假设您无法更改函数对象和目标签名的调用表达式,则可以包装rvalue引用并通过const ref传递包装对象(临时)。 从本质上讲,通话扩展为:f( wrap(move(o)) );

我怀疑完美转发存在问题,因为绑定i = bind(&f);不起作用;因此,我引入了一个执行完美转发的中间步骤,以便将呼叫解析为: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;
}