在统一初始化语法中使用std :: move in C ++ 11 move constructor

时间:2013-04-07 15:43:53

标签: c++ c++11 move move-constructor

我有这个简单的课程:

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

1 个答案:

答案 0 :(得分: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确实如此。