問題の再現に使用できるソース コードは次のとおりです。
#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] でも議論されています。