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

            Bug ID: 122313
           Summary: std::vector<T>::insert(const_iterator, InputIt,
                    InputIt) should allow *InputIt with convertible type
           Product: gcc
           Version: 16.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: vanantwerpenjeroen at gmail dot com
  Target Milestone: ---

````
#include <vector>

struct S{ 
    int i;
};

int main()
{
    std::vector<int> base_v;
    std::vector<S> v;
    v.insert(v.end(), base_v.begin(),base_v.end());
}
````
[Code on Compiler-Explorer.com, using latest
version](https://compiler-explorer.com/z/ET388MbWW)

In this snippet, the overload `template< class InputIt > iterator insert(
const_iterator pos, InputIt first, InputIt last );` is used.

To my understanding, this should work when using in input iterator to a
convertible type.

>From https://en.cppreference.com/w/cpp/container/vector/insert.html:
> 4) Inserts elements from range [first, last) before pos.
>
> This overload has the same effect as overload (3) if InputIt is an integral 
> type.     (until C++11)
> 
> This overload participates in overload resolution only if InputIt satisfies 
> the requirements of LegacyInputIterator.  (since C++11)
>
> If any of the following conditions is satisfied, the behavior is undefined:
>   - T is not EmplaceConstructible into vector from *first. (since C++11)
>   - T is not MoveInsertable into vector. (since C++11)
>   - T does not satisfy the requirements of MoveConstructible, MoveAssignable 
> or Swappable.  (since C++11)
>   - first or last are iterators into *this. 

Given that `S` is EmplaceConstructible from `int`, I would expect this code to
work.
Both libc++ and msvc STL accept this code.

>From https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/n4849.pdf: (C++20
standard draft)
- 22.3.11.5 Modifiers [vector.modifiers])
  > Remarks: Causes reallocation if the new size is greater than the old
capacity. Reallocation invalidates
  > all the references, pointers, and iterators referring to the elements in
the sequence, as well as the past-
  > the-end iterator. If no reallocation happens, then references, pointers,
and iterators before the insertion
  > point remain valid but those at or after the insertion point, including the
past-the-end iterator, are
  > invalidated. If an exception is thrown other than by the copy constructor,
move constructor, assignment
  > operator, or move assignment operator of T or by any InputIterator
operation there are no effects.
  > If an exception is thrown while inserting a single element at the end and T
is Cpp17CopyInsertable
  > or is_nothrow_move_constructible_v<T> is true, there are no effects.
Otherwise, if an exception is
  > thrown by the move constructor of a non-Cpp17CopyInsertable T, the effects
are unspecified.

- 20.10.11 Specialized algorithms [specialized.algorithms]
> If an algorithm’s template parameter is named InputIterator, the template 
> argument shall meet the
Cpp17InputIterator requirements (23.3.5.2).


- 23.3.5.1 Cpp17Iterator [iterator.iterators]
  > | Expression | Return type | Operational semantics | Assertion/note
pre-/post-condition    | 
  > | *r         | unspecified |                       |  Preconditions: r is
dereferenceable. | 
- 23.3.5.2 Input iterators [input.iterators]
  > | Expression | Return type                 | Operational semantics |
Assertion/note pre-/post-condition                                             
                                                                              
|
  > | *a         | reference, convertible to T |                       |
Preconditions: a is dereferenceable. The expression (void)*a, *a is equivalent
to *a. If a == b and (a, b) is in the domain of == then *a is equivalent to *b.
|

I'm assuming the requirement of InputIterator on algorithms is the same as on
containers, as this is not explicitly specified.

Given those fragments, I believe the statement of CppReference to be correct.

Nowhere it mentions that `std::declval<T &>() = *std::declval<InputIterator>()`
needs to be satisfied, while this is relied on by libstdc++.

The C++23 standard draft
(https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/n4950.pdf) has the
same statements.

Reply via email to