似乎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会议上宣布。
答案 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;
}