is_assignable 和 std::unique_ptr

2024-01-06

Here https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/testsuite/20_util/unique_ptr/dr2228.cc是来自 gcc 的测试文件,现场演示 https://wandbox.org/permlink/ygtnv3Zm1fMlc1zY

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.    
}

std::is_assignable https://en.cppreference.com/w/cpp/types/is_assignable

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

std::declval https://en.cppreference.com/w/cpp/utility/declval:

template<class T>
typename std::add_rvalue_reference<T>::type declval() noexcept;

返回类型是T&& unless T是(可能是 cv 限定的)void,在这种情况下返回类型是 T。

让我们看看MoveAssignOnly:

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

int main()
{
    static_assert(
    not std::is_assignable<MoveAssignOnly, MoveAssignOnly>::value, "");
}

现场演示 https://wandbox.org/permlink/5vl6kQmmR0LJv8XP:

error: static_assert failed due to requirement '!std::is_assignable<MoveAssignOnly, MoveAssignOnly>::value'

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

让我们回到gcc的测试文件 https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/testsuite/20_util/unique_ptr/dr2228.cc and std::unique_ptr。据我们所知,std::unique_ptr还有移动任务 https://github.com/llvm-mirror/libcxx/blob/master/include/memory#L321.

然而,与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 be 不可分配(! is_assignable) when std::unique_ptr提供移动任务?


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

unique_ptr还提供了一个赋值运算符模板,允许从右值进行赋值unique_ptr使用不同的删除器,但删除器必须是可分配的(请参阅参考 https://en.cppreference.com/w/cpp/memory/unique_ptr/operator%3D)。因此,您可以通过使删除器可分配来触发静态断言:

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.    
}

[实例] http://coliru.stacked-crooked.com/a/8667188dc6227c01

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

is_assignable 和 std::unique_ptr 的相关文章

随机推荐