is_assignable和std :: unique_ptr

陳 力*_*陳 力 6 c++ move assignment-operator

是gcc的一个测试文件,现场演示

struct do_nothing
{
    template <class T>
    void operator()(T*) {}
};

int
main()
{
    int i = 0;
    std::unique_ptr<int, do_nothing> p1(&i);
    std::unique_ptr<int> p2;
    static_assert(!std::is_assignable<decltype(p2), decltype(p1)>::value, ""); // note ! here.    
}
Run Code Online (Sandbox Code Playgroud)

std::is_assignable

如果表达式std::declval<T>() = std::declval<U>()在未评估的上下文中格式良好,则提供成员常量值等于true.否则,值为false.从与任一类型无关的上下文执行访问检查.

std::declval:

template<class T>
typename std::add_rvalue_reference<T>::type declval() noexcept;
Run Code Online (Sandbox Code Playgroud)

返回类型是T&&除非T(可能是cv-qualified)void,在这种情况下返回类型是T.

我们来看看MoveAssignOnly:

struct MoveAssignOnly {
  MoveAssignOnly &operator=(MoveAssignOnly &) = delete;
  MoveAssignOnly &operator=(MoveAssignOnly &&) = default;
};

int main()
{
    static_assert(
    not std::is_assignable<MoveAssignOnly, MoveAssignOnly>::value, "");
}
Run Code Online (Sandbox Code Playgroud)

现场演示:

error: static_assert failed due to requirement '!std::is_assignable<MoveAssignOnly, MoveAssignOnly>::value'
Run Code Online (Sandbox Code Playgroud)

是的,它无法编译,因为它提供了移动分配

让我们回到gcc的测试文件std::unique_ptr.众所周知,std::unique_ptr也有移动任务.

然而,不像struct MoveAssignOnly, static_assert(!std::is_assignable<decltype(p2), decltype(p1)>::value, "");(更清楚地,static_assert(!std::is_assignable<std::unique_ptr<int>, std::unique_ptr<int, do_nothing>>::value, "");编译愉快.

我一直在努力与libcxx的实施unique_ptr 时间长,但仍然想不通:怎么能std::unique_ptr不可转让(! is_assignable)时std::unique_ptr提供移动分配?

Rei*_*ica 4

p1并且p2属于不同类型。与 with 不同shared_ptr,a 的删除器unique_ptr是指针类型的一部分。unique_ptr这意味着如果两个删除器类型不同,则移动分配运算符不允许您在两个 s 之间进行分配(甚至移动分配) 。

unique_ptr还提供了一个赋值运算符模板,允许从unique_ptr具有不同删除器的右值进行赋值,但删除器必须是可赋值的(请参阅参考资料)。因此,您可以通过使删除器可分配来触发静态断言:

struct do_nothing
{
    template <class T>
    void operator()(T*) {}

    template <class T>
    operator std::default_delete<T>() { return {}; }
};

int
main()
{
    int i = 0;
    std::unique_ptr<int, do_nothing> p1(&i);
    std::unique_ptr<int> p2;
    static_assert(!std::is_assignable<decltype(p2), decltype(p1)>::value, ""); // note ! here.    
}
Run Code Online (Sandbox Code Playgroud)

[实例]