Используйте std :: move в C ++ 11 конструкторе перемещения с единым синтаксисом инициализации

У меня есть этот простой класс:

struct Worker
{
Worker() : done{false} {}
Worker(const Worker& rhs) : done{rhs.done}, qworker{} {}
Worker(Worker &&rhs) : done{rhs.done}
{
qworker = std::move(rhs.qworker);
}
...
}

это нормально скомпилируется с gcc-4.7.2, но если я пытаюсь использовать эту версию, я получаю ошибку

struct Worker
{
Worker() : done{false} {}
Worker(const Worker& rhs) : done{rhs.done}, qworker{} {}
Worker(Worker &&rhs) : done{rhs.done}
, qworker{std::move(rhs.qworker)} // <- ERROR
{
}
...
}

Зачем?

In file included from tlog.cpp:8:0:
log11.hpp: In member function ‘void Log11::Worker::run()’:
log11.hpp:34:29: error: ‘class std::vector<std::function<void()> >’ has no member named ‘pop_front’
In file included from /usr/include/c++/4.7/thread:39:0,
from tlog.cpp:3:
/usr/include/c++/4.7/functional: In instantiation of ‘static void std::_Function_handler<void(_ArgTypes ...), _Functor>::_M_invoke(const std::_Any_data&, _ArgTypes ...) [with _Functor = std::vector<std::function<void()> >; _ArgTypes = {}]’:
/usr/include/c++/4.7/functional:2298:6:   required from ‘std::function<_Res(_ArgTypes ...)>::function(_Functor, typename std::enable_if<(! std::is_integral<_Functor>::value), std::function<_Res(_ArgTypes ...)>::_Useless>::type) [with _Functor = std::vector<std::function<void()> >; _Res = void; _ArgTypes = {}; typename std::enable_if<(! std::is_integral<_Functor>::value), std::function<_Res(_ArgTypes ...)>::_Useless>::type = std::function<void()>::_Useless]’
log11.hpp:20:78:   required from here
/usr/include/c++/4.7/functional:1926:2: error: no match for call to ‘(std::vector<std::function<void()> >) ()’

3

Решение

Согласно стандарту C ++ 11 std::function имеет шаблон конструктора без ограничений, который принимает любой тип аргумента:

template<class F> function(F f);

Когда ты сказал qworker{std::move(rhs.qworker)} эта первая попытка вызвать конструктор, принимающий std::initializer_list<std::function<void()>>, Из-за шаблона конструктора без ограничений, показанного выше, std::function<void()> может быть построен из любой типа, так что вы получите initializer_list с одним участником, вот так:

{ std::function<void()>{std::move(rhs.qworker)} }

Это неверно, потому что rhs.qworker не является вызываемым объектом, но ошибка возникает только при попытке вызвать функциональные объекты.

Если вы говорите qworker(std::move(rhs.qworker)) тогда конструктор списка инициализатора не является кандидатом, и вместо этого вызывается конструктор перемещения.

Отчет о дефекте соответствует стандарту (LWG 2132) который исправляет это, предотвращая function(F) вызывается шаблон конструктора, если аргумент не является вызываемым объектом. Что мешает initializer_list<function<void()>> создается, а вместо qworker{std::move(rhs.qworker)} вызывает конструктор перемещения, как и предполагалось. GCC 4.7 не реализует разрешение для LWG 2132, но GCC 4.8 делает.

3

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

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

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