Почему назначение возвращаемого значения boost :: move () неконстантной ссылке не работает в режиме C ++ 0x, но работает в режиме C ++ 03

Вот исходный код, который можно использовать для воспроизведения проблемы:

#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));
}

При использовании режима C ++ 03 в GCC код компилируется без проблем. С другой стороны, использование режима 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 + неконстантный ref как тип возвращаемого значения).

Я использую gcc v4.6.3, Boost 1.54.0 и Ubuntu 12.04 (i386).

ОБНОВЛЕНИЕ 1: я сделал тестовый пример немного более реалистичным. Цель состоит в том, чтобы иметь универсальную функцию, которая вызывает функтор под блокировкой и возвращает значение, возвращаемое функтором через boost :: move (), поскольку тип возвращаемого значения может быть подвижным, но не копируемым (что в некоторых случаях является истинным). из моих призывов call_under_lock()).

ОБНОВЛЕНИЕ 2: Оказывается, подобная проблема может наблюдаться при использовании clang 3.5.1~(exp) в режиме 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-пользователей [1].

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

2

Решение

В чем причина такой неудачи?

В C ++ 03 R является std::ostream&, а также boost::move() очевидно, возвращает тот же тип, и поэтому нет проблем.

В C ++ 11 R по-прежнему std::ostream&, тем не мение boost::move() вернусь std::ostream&&, Это делает выражение boost::move() rvalue, которое не может быть привязано к неконстантной ссылке lvalue.

Есть ли способ обойти это в режиме C ++ 11?

Да:

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

Это должно делать именно то, что вы хотите и в C ++ 03, и в C ++ 11. Он будет двигаться, когда вы хотите, и не будет двигаться, когда вы не хотите.

3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]