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
提供移动任务?