0

Visual C++std::function<>は、右辺値参照を引数として持つ関数を処理しないようです。誰でも回避策を提案できますか?

#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 を使用していません (したがって、この問題ではありません)。

調査後の更新:コードは Clang でコンパイルされるため、Microsoft のバグであると確信しています。これは、VC11 で修正されたものである可能性があります: 649274

アップデートの修正: VC11 では MS のバグは修正されていません。リンクから:

最初の機会は、GoingNative 2012 カンファレンスで Herb Sutter が発表した VC11 と VC12 の間の「アウト オブ バンド」リリースです。

4

1 に答える 1

1

ここでどのような回避策が必要かわかりません。関数オブジェクトの呼び出し式とターゲット シグネチャを変更できないと仮定すると、右辺値参照をラップし、ラップされたオブジェクト (一時オブジェクト) を 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;
}
于 2013-04-22T21:55:02.357 に答える