is_assignable 和 std::unique_ptr
is_assignable and std::unique_ptr
Here is a test file from gcc, live demo
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.
}
If the expression std::declval<T>() = std::declval<U>()
is well-formed in unevaluated context, provides the member constant value equal true. Otherwise, value is false. Access checks are performed as if from a context unrelated to either type.
template<class T>
typename std::add_rvalue_reference<T>::type declval() noexcept;
The return type is T&&
unless T
is (possibly cv-qualified) void, in which case the return type is T.
我们来看看MoveAssignOnly
:
struct MoveAssignOnly {
MoveAssignOnly &operator=(MoveAssignOnly &) = delete;
MoveAssignOnly &operator=(MoveAssignOnly &&) = default;
};
int main()
{
static_assert(
not std::is_assignable<MoveAssignOnly, MoveAssignOnly>::value, "");
}
error: static_assert failed due to requirement '!std::is_assignable<MoveAssignOnly, MoveAssignOnly>::value'
是的,编译失败,因为它提供了移动赋值
让我们return到gcc's test file and std::unique_ptr
. As we know, std::unique_ptr
also has move assignments。
然而,与 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
提供移动分配时?
p1
和 p2
是不同的类型。与 shared_ptr
不同,unique_ptr
的删除器是指针类型的一部分。这意味着如果删除器类型不同,移动赋值运算符不允许您在两个 unique_ptr
之间进行赋值(甚至移动赋值)。
unique_ptr
还提供了一个赋值运算符模板,它允许使用不同的删除器从 unique_ptr
的右值进行分配,但删除器必须是可分配的(参见 reference)。因此,您可以通过使删除器可分配来使静态断言触发:
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.
}
Here is a test file from gcc, live demo
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.
}
If the expression
std::declval<T>() = std::declval<U>()
is well-formed in unevaluated context, provides the member constant value equal true. Otherwise, value is false. Access checks are performed as if from a context unrelated to either type.
template<class T>
typename std::add_rvalue_reference<T>::type declval() noexcept;
The return type is
T&&
unlessT
is (possibly cv-qualified) void, in which case the return type is T.
我们来看看MoveAssignOnly
:
struct MoveAssignOnly {
MoveAssignOnly &operator=(MoveAssignOnly &) = delete;
MoveAssignOnly &operator=(MoveAssignOnly &&) = default;
};
int main()
{
static_assert(
not std::is_assignable<MoveAssignOnly, MoveAssignOnly>::value, "");
}
error: static_assert failed due to requirement '!std::is_assignable<MoveAssignOnly, MoveAssignOnly>::value'
是的,编译失败,因为它提供了移动赋值
让我们return到gcc's test file and std::unique_ptr
. As we know, std::unique_ptr
also has move assignments。
然而,与 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
提供移动分配时?
p1
和 p2
是不同的类型。与 shared_ptr
不同,unique_ptr
的删除器是指针类型的一部分。这意味着如果删除器类型不同,移动赋值运算符不允许您在两个 unique_ptr
之间进行赋值(甚至移动赋值)。
unique_ptr
还提供了一个赋值运算符模板,它允许使用不同的删除器从 unique_ptr
的右值进行分配,但删除器必须是可分配的(参见 reference)。因此,您可以通过使删除器可分配来使静态断言触发:
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.
}