Use std::move in C++11 move constructor with uniform initialization syntax

喜你入骨 提交于 2019-12-19 09:57:08

问题


I have this simple class:

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

this compile fine with gcc-4.7.2 but if I try to use this version I obtain an error

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
        {
        }
...
}

Why?

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()> >) ()’

回答1:


According to the C++11 standard std::function has an unconstrained constructor template that accepts any argument type:

template<class F> function(F f);

When you say qworker{std::move(rhs.qworker)} this first attempts to call a constructor taking std::initializer_list<std::function<void()>>. Because of the unconstrained constructor template shown above, a std::function<void()> can be constructed from any type, so you get an initializer_list with one member, like this:

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

This is invalid, because rhs.qworker is not a callable object, but the error only happens when you try to invoke the function objects.

If you say qworker(std::move(rhs.qworker)) then the initializer list constructor is not a candidate and the move constructor is called instead.

There is a defect report against the standard (LWG 2132) which fixes this by preventing the function(F) constructor template being called unless the argument is a callable object. That prevents an initializer_list<function<void()>> being created, and instead qworker{std::move(rhs.qworker)} calls the move constructor, as intended. GCC 4.7 does not implement the resolution for LWG 2132, but GCC 4.8 does.



来源:https://stackoverflow.com/questions/15864269/use-stdmove-in-c11-move-constructor-with-uniform-initialization-syntax

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!