On Sun, 2 Oct 2022 at 22:58, Barry Revzin <barry.revzin@gmail.com> wrote:


On Sun, Oct 2, 2022 at 4:47 PM Edward Catmur via Std-Discussion <std-discussion@lists.isocpp.org> wrote:
On Sun, 2 Oct 2022 at 22:00, Aleksander Maciej Miera via Std-Discussion <std-discussion@lists.isocpp.org> wrote:
Hello,

While fiddling with template metaprogramming I managed to run into an
issue related to some std:: containers and type traits. As far as I have
researched it, it is a known (although not obvious at first) shortcoming.

Consider the following code snippet:

#include <type_traits>
#include <memory>
#include <vector>

struct Copyable{};
using MoveOnly = std::unique_ptr<Copyable>;

static_assert(!std::is_copy_constructible_v<std::vector<MoveOnly>>);

(BTW, the vector is used here as an example, but the list and
forward_list also behave the same way for the same reason)

Counter-intuitively, the static assert fails. This stems from the fact
that the vector's copy constructor is not a function template; thus it
cannot be SFINAEd (everything can be a verb if one tries hard enough ;))
away, because it's always declared.

Since C++20, the copy constructor can be constrained:

    vector(vector const&) requires std::copyable<T>;

I think this would solve your issue. This would require the containers general requirements to lift this requirement (on `X u(a)`, that `T` is Cpp17CopyInsertable, etc.) from a precondition to a constraint. There are probably quite a few clauses that would need to be considered in such an effort.

The issue is that vector<T> supports T being incomplete. So if you did that, then:

struct Node;
vector<Node> nodes;
 
Would instantiate the copy constructor which would error on Node being incomplete. So you'd have to come up with a way for vector<Incomplete> to still work. 

Isn't that ill-formed already as it instantiates the default and allocator ctors? Or have I misunderstood [vector.overview]/4?