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

前端 未结 1 2002
自闭症患者
自闭症患者 2021-01-14 15:49

I have this simple class:

struct Worker
{
        Worker() : done{false} {}
        Worker(const Worker& rhs) : done{rhs.done}, qworker{} {}
        Work         


        
相关标签:
1条回答
  • 2021-01-14 16:46

    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.

    0 讨论(0)
提交回复
热议问题