【问题标题】:Use std::move in C++11 move constructor with uniform initialization syntax在具有统一初始化语法的 C++11 移动构造函数中使用 std::move
【发布时间】:2013-04-07 15:43:53
【问题描述】:

我有这个简单的课程:

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

【问题讨论】:

  • qworker的类型是什么?
  • std::deque<:function>> qworker;
  • 嗯,这可能是一个错误。它在 GCC 4.8.0 上编译(参见 here
  • 感谢安迪刚刚在 4.8 上测试,我可以确认:现在编译! :(这是一个错误?
  • @Gian 将大括号更改为括号,它将在 gcc 4.7.2 上编译。 qworker(std::move(rhs.qworker))

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


【解决方案1】:

根据 C++11 标准 std::function 有一个接受任何参数类型的不受约束的构造函数模板:

template<class F> function(F f);

当您说qworker{std::move(rhs.qworker)} 时,这首先会尝试调用采用std::initializer_list&lt;std::function&lt;void()&gt;&gt; 的构造函数。由于上面显示的不受约束的构造函数模板,std::function&lt;void()&gt; 可以从 any 类型构造,因此您会得到一个带有一个成员的 initializer_list,如下所示:

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

这是无效的,因为rhs.qworker 不是可调用对象,但只有在您尝试调用函数对象时才会发生错误。

如果你说qworker(std::move(rhs.qworker)),那么初始化列表构造函数不是候选者,而是调用移动构造函数。

有一个针对标准 (LWG 2132) 的缺陷报告,该标准通过防止调用 function(F) 构造函数模板来解决此问题,除非参数是可调用对象。这可以防止创建 initializer_list&lt;function&lt;void()&gt;&gt;,而是按预期调用移动构造函数 qworker{std::move(rhs.qworker)}。 GCC 4.7 没有实现 LWG 2132 的解决方案,但 GCC 4.8 可以。

【讨论】:

    猜你喜欢
    • 2015-08-05
    • 2015-03-21
    • 1970-01-01
    • 2012-10-19
    • 2017-03-06
    • 1970-01-01
    • 2016-10-02
    • 2020-05-05
    相关资源
    最近更新 更多