为什么 std::is_copy_constructible_v<std::vector<MoveOnlyType>> 是真的?
Why is std::is_copy_constructible_v<std::vector<MoveOnlyType>> true?
在我的 clang 和 libc++ 版本中(接近 HEAD
),这个 static_assert
通过:
static_assert(std::is_copy_constructible_v<std::vector<std::unique_ptr<int>>>)
当然,如果你真的尝试复制构造一个唯一指针的向量,它会编译失败:
../include/c++/v1/__memory/allocator.h:151:28: error: call to implicitly-deleted copy constructor of 'std::unique_ptr<int>'
::new ((void*)__p) _Up(_VSTD::forward<_Args>(__args)...);
[...]
note: in instantiation of member function 'std::vector<std::unique_ptr<int>>::vector' requested here
const std::vector<std::unique_ptr<int>> bar(foo);
^
../include/c++/v1/__memory/unique_ptr.h:215:3: note: copy constructor is implicitly deleted because 'unique_ptr<int>' has a user-declared move constructor
unique_ptr(unique_ptr&& __u) _NOEXCEPT
我假设这种情况是因为 std::vector<T>
实现在 T
不可复制构造时不使用 SFINAE 来禁用复制构造函数。但为什么不呢?标准中是否有说明必须以这种方式工作?这很不幸,因为这意味着我自己关于复制可构造性的 SFINAE 并没有围绕向量做正确的事情。
std::vector
等容器(std::array
除外)都指定了拷贝构造函数。这未指定以元素类型是否可复制为条件。如果元素类型不可复制,则仅禁止实例化复制构造函数的定义。
因此,容器上的 std::is_copy_constructible_v
将始终为 true
。无法测试定义的实例化是否 well-formed 具有类型特征。
如果元素类型不可复制,则可以指定不声明复制构造函数或将其排除在重载决策之外。但是,这会附带一个 trade-off,在这个博客 post 中有详细解释:https://quuxplusone.github.io/blog/2020/02/05/vector-is-copyable-except-when-its-not/.
简而言之,如果我们希望能够使用类型不完整的容器,例如递归地喜欢
struct X {
std::vector<X> x;
};
那么实例化容器class时,我们无法判断X
是否可复制。因此复制构造函数的声明不能依赖于这个 属性.
自 C++17 起,标准要求 std::vector
、std::list
和 std::forward_list
,但其他容器不需要,以像这样处理不完整的类型。
在我的 clang 和 libc++ 版本中(接近 HEAD
),这个 static_assert
通过:
static_assert(std::is_copy_constructible_v<std::vector<std::unique_ptr<int>>>)
当然,如果你真的尝试复制构造一个唯一指针的向量,它会编译失败:
../include/c++/v1/__memory/allocator.h:151:28: error: call to implicitly-deleted copy constructor of 'std::unique_ptr<int>'
::new ((void*)__p) _Up(_VSTD::forward<_Args>(__args)...);
[...]
note: in instantiation of member function 'std::vector<std::unique_ptr<int>>::vector' requested here
const std::vector<std::unique_ptr<int>> bar(foo);
^
../include/c++/v1/__memory/unique_ptr.h:215:3: note: copy constructor is implicitly deleted because 'unique_ptr<int>' has a user-declared move constructor
unique_ptr(unique_ptr&& __u) _NOEXCEPT
我假设这种情况是因为 std::vector<T>
实现在 T
不可复制构造时不使用 SFINAE 来禁用复制构造函数。但为什么不呢?标准中是否有说明必须以这种方式工作?这很不幸,因为这意味着我自己关于复制可构造性的 SFINAE 并没有围绕向量做正确的事情。
std::vector
等容器(std::array
除外)都指定了拷贝构造函数。这未指定以元素类型是否可复制为条件。如果元素类型不可复制,则仅禁止实例化复制构造函数的定义。
因此,容器上的 std::is_copy_constructible_v
将始终为 true
。无法测试定义的实例化是否 well-formed 具有类型特征。
如果元素类型不可复制,则可以指定不声明复制构造函数或将其排除在重载决策之外。但是,这会附带一个 trade-off,在这个博客 post 中有详细解释:https://quuxplusone.github.io/blog/2020/02/05/vector-is-copyable-except-when-its-not/.
简而言之,如果我们希望能够使用类型不完整的容器,例如递归地喜欢
struct X {
std::vector<X> x;
};
那么实例化容器class时,我们无法判断X
是否可复制。因此复制构造函数的声明不能依赖于这个 属性.
自 C++17 起,标准要求 std::vector
、std::list
和 std::forward_list
,但其他容器不需要,以像这样处理不完整的类型。