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.