C++ Logo

std-discussion

Advanced search

Re: some containers always copy constructible according to type_traits

From: Edward Catmur <ecatmur_at_[hidden]>
Date: Mon, 3 Oct 2022 09:42:40 +0100
On Sun, 2 Oct 2022 at 23:39, Barry Revzin <barry.revzin_at_[hidden]> wrote:

>
>
> On Sun, Oct 2, 2022 at 5:25 PM Edward Catmur <ecatmur_at_[hidden]>
> wrote:
>
>>
>>
>> On Sun, 2 Oct 2022 at 22:58, Barry Revzin <barry.revzin_at_[hidden]> wrote:
>>
>>>
>>>
>>> On Sun, Oct 2, 2022 at 4:47 PM Edward Catmur via Std-Discussion <
>>> std-discussion_at_[hidden]> wrote:
>>>
>>>> On Sun, 2 Oct 2022 at 22:00, Aleksander Maciej Miera via Std-Discussion
>>>> <std-discussion_at_[hidden]> 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?
>>
>
> Fine:
>
> struct Node {
> vector<Node> nodes;
> };
>

Ah, yeah. Ugh, why do we have to evaluate constraints so early...

Received on 2022-10-03 08:42:52