2

問題の再現に使用できるソース コードは次のとおりです。

#include <iostream>
#include <boost/bind.hpp>
#include <boost/move/move.hpp>
#include <boost/ref.hpp>

std::ostream& dump_to_stream(std::ostream& os, int a, int b) {
  return os << a << '\n' << b << '\n';
}

template <class R, class F>
R call_under_lock(F f) {
  // lock();
  R r = f();
  // unlock();
  return boost::move(r);
}

int main() {
  std::ostream& os = call_under_lock<std::ostream&>(
    boost::bind(&dump_to_stream, boost::ref(std::cout), 1, 2));
}

GCC で C++03 モードを使用すると、コードは問題なくコンパイルされます。一方、C++0x モードを使用すると、次のエラーが発生します。

$ g++ -I../../boost_latest -std=c++0x -O2 -Wall -Wextra   -c -o test.o test.cpp
(...)
test.cpp: In function ‘R call_under_lock(F) [with R = std::basic_ostream<char>&, F = boost::_bi::bind_t<std::basic_ostream<char>&, std::basic_ostream<char>& (*)(std::basic_ostream<char>&, int, int), boost::_bi::list3<boost::reference_wrapper<std::basic_ostream<char> >, boost::_bi::value<int>, boost::_bi::value<int> > >]’:
test.cpp:20:62:   instantiated from here
test.cpp:15:23: error: invalid initialization of non-const reference of type ‘std::basic_ostream<char>&’ from an rvalue of type ‘boost::remove_reference<std::basic_ostream<char>&>::type {aka std::basic_ostream<char>}’
(...)

そのような失敗の理由は何ですか?C++11 モードで回避する方法はありますか?

上記のコードは、私が一般的なコードで使用するものを簡略化したものです。したがって、そのような組み合わせ ( boost::move+ 戻り値の型としての非 const ref) が必要です。

gcc v4.6.3、Boost 1.54.0、および Ubuntu 12.04 (i386) を使用しています。

更新 1: テスト ケースをもう少し現実的なものにしました。目標は、ロックの下でファンクターを呼び出し、boost::move() を介してファンクターによって返された値を返すジェネリック関数を持つことです。の私の呼び出しのcall_under_lock())。

clang 3.5.1~(exp)更新 2: C++11 モードで使用すると、同様の問題が発生することが判明しました。

$ clang test.cpp -I../../boost_latest/ -lstdc++ --std=c++11
test.cpp:11:10: error: non-const lvalue reference to type 'basic_ostream<[2 * ...]>' cannot bind to a temporary of type 'basic_ostream<[2 * ...]>'
  return boost::move(r);
         ^~~~~~~~~~~~~~
test.cpp:19:22: note: in instantiation of function template specialization 'call_under_lock<std::basic_ostream<char> &, boost::_bi::bind_t<std::basic_ostream<char> &, std::basic_ostream<char> &(*)(std::basic_ostream<char> &, int, int),
      boost::_bi::list3<boost::reference_wrapper<std::basic_ostream<char> >, boost::_bi::value<int>, boost::_bi::value<int> > > >' requested here
  std::ostream& os = call_under_lock<std::ostream&>(

更新 3: このトピックは、boost-users メーリング リスト [1] でも議論されています。

[1] http://boost.2283326.n4.nabble.com/move-differences-between-results-in-C-03-and-C-11-modes-td4659264.html

4

1 に答える 1

3

そのような失敗の理由は何ですか?

C++03 では、R はstd::ostream&であり、boost::move()明らかに同じ型を返すため、問題はありません。

C++11 では、R はまだ ですがstd::ostream&boost::move()を返しstd::ostream&&ます。これにより、式boost::move()が右辺値になり、非 const 左辺値参照にバインドできなくなります。

C++11 モードで回避する方法はありますか?

はい:

template <class R, class F>
R call_under_lock(F f) {
  // lock();
  R r = f();
  // unlock();
  return r;
}

これは、C++03 と C++11 の両方で必要なことを正確に行う必要があります。動かしたい時に動き、望まない時は動かさない。

于 2014-02-12T18:30:01.773 に答える