对于不可复制的值类型,容器的复制构造函数是否可以定义为已删除?

Can copy constructors of containers be defined as deleted for non-copyable value types?

如果我们有一个具有不可复制值类型的容器,这样的容器class仍然定义了复制构造函数 , 只是它可能不会被调用。

using T = std::vector<std::unique_ptr<int>>;
std::cout << std::is_copy_constructible_v<T>; // prints out "1" (libstdc++)

这可能会导致 "hidden" 问题,例如此处讨论的问题:

我的问题是标准库实现是否可以将这样的复制构造函数定义为有条件删除,即在不可复制值类型的情况下删除.这对我来说非常有意义(至少在有 C++ 概念之前)。这样的实施是否符合标准?

简短回答:没有。 如果我们查看 std::vector 的当前规范(截至 c++17),我们有以下签名和描述:

vector(const vector& other);

Copy constructor. Constructs the container with the copy of the contents of other. If alloc is not provided, allocator is obtained as if by calling std::allocator_traits::select_on_container_copy_construction(other.get_allocator()).

复制构造函数具有通常的规范签名,并且描述未指定任何 SFINAE 条件,因此符合要求的实现不应强加条件删除等更严格的要求。然而,如果尝试对 vector<unique_ptr<T>> 的复制构造函数进行显式或隐式调用,则会发生实例化错误,因为描述暗示了逐元素复制。因此,vector<unique_ptr<T>> 不满足 CopyConstructible 要求,这很像删除了复制构造函数。

据我所知,条件删除没有语法支持,但 SFINAE 条件和即将到来的约束可以实现选择性重载解析。我仍然强烈建议不要在特殊行动中使用这些。应使用其通常的规范签名来定义特殊操作。

这在数学上是不可能的,因为 vector 得到了不完整的类型支持:

struct E {
    std::vector<E> e;
};

E 是可复制的当且仅当 std::vector<E> 是可复制的,std::vector<E> 是可复制的当且仅当 E 是可复制的。乌龟一路下来。

甚至在此之前,因为分配器的 construct 可以在它认为合适的时候破坏构造函数参数,并且容器无法判断某些东西是否 "allocator-constructible",有条件地删除复制构造函数需要一些认真的设计工作。不完整的类型支持只是钉在棺材里。

如T.C。说这甚至可能不可行,但如果我相信 符合实施 下的 [member.functions]p2 部分不允许这样做:

For a non-virtual member function described in the C++ standard library, an implementation may declare a different set of member function signatures, provided that any call to the member function that would select an overload from the set of declarations described in this document behaves as if that overload were selected. [ Note: For instance, an implementation may add parameters with default values, or replace a member function with default arguments with two or more member functions with equivalent behavior, or add additional signatures for a member function name. — end note  ]