https://gcc.gnu.org/bugzilla/show_bug.cgi?id=122313

--- Comment #4 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to Jonathan Wakely from comment #3)
> Here's a C++17 test that doesn't rely on parenthesized init of aggregates:
> 
> #include <vector>
> #include <memory_resource>
> 
> void test1()
> {
> #if __cplusplus >= 202002L
>   struct S { int i; };
>   static_assert(std::is_constructible_v<S, int&>);
> 
>   std::vector<int> base_v;
>   std::vector<S> v;
>   v.insert(v.end(), base_v.begin(), base_v.end());
> #endif
> }

This should construct S(int) and insert that, not just do *pos = *first.

Constructing S(int) using aggregate-init is needed, we can't assume
is_convertible_v<int&, S> or is_assignable_v<S&, int&>.


> void test2()
> {
>   struct S { explicit S(int) { } };
>   static_assert(std::is_constructible_v<S, int&>);
> 
>   std::vector<int> base_v;
>   std::vector<S> v;
>   v.insert(v.end(), base_v.begin(), base_v.end());
> }

Same here, but constructing S(int) uses an explicit constructor.

> void test3()
> {
>   struct S {
>     S(int) { }
>     void operator=(int) = delete;
>   };
>   static_assert(std::is_constructible_v<S, int&>);
> 
>   std::vector<int> base_v;
>   std::vector<S> v;
>   v.insert(v.end(), base_v.begin(), base_v.end());
> }

This time the constructor is implicit, but the assignment is deleted, so no
implicit conversion is attempted.

> void test4()
> {
>   struct S {
>     using allocator_type = std::pmr::polymorphic_allocator<S>;
>     S() { }
>     S(allocator_type) { }
>     S(int) { throw; }
>     S(int, allocator_type) { }
>     S(const S&, allocator_type) { }
>   };
>   static_assert(std::is_constructible_v<S, int&>);
> 
>   std::vector<int> base_v(1);
>   std::pmr::vector<S> v(1);
>   v.reserve(2);
>   v.insert(v.begin(), base_v.begin(), base_v.end());
> }

This one compiles, but does an implicit conversion from int& to S, which uses
the throwing constructor.

Cpp17EmplaceConstructible into vector using int& means constructing an S
properly using allocator_traits::construct, which would use S(int,
allocator_type) not S(int).


One more failing test:

void test5()
{
  struct S
  {
    S() { }
    S(const S&) { }
    S& operator=(S&&) { return *this; }
  };

  S base_v[1];
  std::vector<S> v;
  v.insert(v.end(), base_v, base_v+1);
}

Here S meets all the requirements for vector::insert(const_iterator, Iter,
Iter), it is 
C++17EmplaceConstructible into vector from S&, it is Cpp17MoveInsertable and
Cpp17MoveAssignable, and CPp17MoveSwappable. But we try to do a copy assignment
inside std::copy.

Reply via email to