代码之家  ›  专栏  ›  技术社区  ›  Chen Li

为什么移动构造函数影响可赋值?

  •  3
  • Chen Li  · 技术社区  · 7 年前

    is_assignable and std::unique_ptr . @安吉告诉我是因为 std::unique_ptr<int, do_nothing> std::unique_ptr<int> 是不同的类型,所以 static_assert(not std::is_assignable<std::unique_ptr<int>, std::unique_ptr<int, do_nothing>>::value, ""); . 所以,我试着:

    template<typename T, typename D>
    struct MoveAssignOnly_V2
    {
        MoveAssignOnly_V2&
        operator=(MoveAssignOnly_V2&)
            = delete;
    
        MoveAssignOnly_V2&
        operator=(MoveAssignOnly_V2&&) noexcept
        {}
    };
    
    int main()
    {
          static_assert(not std::is_assignable_v<MoveAssignOnly_V2<int, float>,
                     MoveAssignOnly_V2<int, double>>);
    }
    

    是的,因为 MoveAssignOnly_V2<int, float> 和 MoveAssignOnly_V2<int, double> 它们是不可分配的。

    但是 ,当我添加移动向量时:

    template<class U, class E>
    MoveAssignOnly_V2(MoveAssignOnly_V2<U, E>&& m) noexcept {}
    

    static_assert fail! (gcc和clang)。

    这里的问题:为什么move构造函数影响是可赋值的?

    更新

    我添加此构造函数的原因是我发现 std::unique_ptr 有一个

    template< class U, class E >
    unique_ptr( unique_ptr<U, E>&& u ) noexcept;
    

    ,这让我有点困惑:既然它有这样一个角色,它怎么可能不可分配呢?因此,我尝试将这样的ctor添加到 MoveAssignOnly_V2 并发布这个问题。这两个答案都很好,但仍然无法解释原因 std::unique\u ptr 当同时具有移动分配和此模板化构造函数时,不可分配。

    2 回复  |  直到 7 年前
        1
  •  4
  •   Community Mohan Dere    6 年前

    以这个代码为例:

    MoveAssignOnly_V2<int, float> lhs;
    MoveAssignOnly_V2<int, double> rhs;
    lhs = stdL::move(rhs);
    

    当转换构造函数时(注意它是 不 移动构造函数)不存在,无法分配 rhs 进入 lhs

    入式 MoveAssignOnly_V2<int, float> (这将创建该类型的临时文件)。然后,可以将分配从临时转移到 lhs .

    double lhs = 3.14;
    float rhs = 42.f;
    lhs = std::move(rhs);
    

    不能单独使用函数声明,必须阅读完整的规范(在标准或规范中) suitable reference )引用有关转换构造函数的链接引用 std::unique_ptr

    此构造函数仅在满足以下所有条件时参与重载解析:

    (a) unique_ptr<U, E>::pointer 可隐式转换为 pointer
    (b) U 不是数组类型
    c) 或者 Deleter E D 或 删除器 E 可隐式转换为 D

    正如你所看到的 unique_ptr

        2
  •  2
  •   llllllllll    7 年前

    您在此处添加的内容:

    template<class U, class E>
    MoveAssignOnly_V2(MoveAssignOnly_V2<U, E>&& m) noexcept {}
    

    不仅是一个移动构造函数,而且是一个可以 MoveAssignOnly_V2<T, D> MoveAssignOnly_V2<U, E> .

    从而构建 MoveAssignOnly_V2<int, float> 从…起 MoveAssignOnly_V2<int, double>> 很好。