Issue 4016: container-insertable checks do not match what container-inserter does (original) (raw)
This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.
4016. _container-insertable_
checks do not match what _container-inserter_
does
Section: 25.5.7 [range.utility.conv] Status: WP Submitter: Jonathan Wakely Opened: 2023-11-24 Last modified: 2024-04-02
Priority: Not Prioritized
View all issues with WP status.
Discussion:
The exposition-only helper _container-inserter_
uses eitherstd::back_inserter
or std::inserter
. Bothstd::back_insert_iterator
and std::insert_iterator
require C::value_type
to be a valid type, and we do not check for that in _container-insertable_
. The insert iterators can also incur a conversion to construct aC::value_type
which then gets moved into the container. Using emplace instead of insert would avoid that temporary object. It's also possible (although arguably not worth caring about) thatrange_value_t<C>
is not the same type asC::value_type
, and that conversion to C::value_type
could be ill-formed (we only check that conversion fromrange_reference_t<R>
to range_value_t<C>
is well-formed).
It seems preferable to remove the use of insert iterators, so that we don't need to check their requirements at all.
[2023-1-26; Rename exposition-only concept and function after reflector discussion.]
[2024-03-11; Reflector poll]
Set status to Tentatively Ready after six votes in favour during reflector poll.
[Tokyo 2024-03-23; Status changed: Voting → WP.]
Proposed resolution:
This wording is relative to N4964.
- Modify 25.5.7.1 [range.utility.conv.general] as indicated:
-4- Let
_container-~~insertable~~appendable_
be defined as follows:```
template<class Container, class Ref>
constexpr bool container-insertableappendable = // exposition only
requires(Container& c, Ref&& ref) {
requires (requires { c.emplace_back(std::forward(ref)); } ||
requires { c.push_back(std::forward(ref)); } ||
requires { c.emplace(c.end(), std::forward(ref)); } ||
requires { c.insert(c.end(), std::forward(ref)); });
};-5- Let
_container-~~inserter~~append_
be defined as follows:template<class Container, class Ref> constexpr auto container-inserterappend(Container& c) { // exposition only if constexpr (requires { c.push_back(declval<Ref>()); }) return back_inserter(c); else return inserter(c, c.end()); return [&c]<class Ref>(Ref&& ref) { if constexpr (requires { c.emplace_back(declval<Ref>()); }) c.emplace_back(std::forward<Ref>(ref)); else if constexpr (requires { c.push_back(declval<Ref>()); }) c.push_back(std::forward<Ref>(ref)); else if constexpr (requires { c.emplace(c.end(), declval<Ref>()); }) c.emplace(c.end(), std::forward<Ref>(ref)); else c.insert(c.end(), std::forward<Ref>(ref)); }; };
- Modify 25.5.7.2 [range.utility.conv.to] as indicated:
(2.1.4) Otherwise, if
- —
constructible_from<C, Args...>
istrue
, and- —
_container-~~insertable~~appendable_<C, range_reference_t<R>>
istrue
:C c(std::forward<Args>(args)...); if constexpr (sized_range<R> && reservable-container<C>) c.reserve(static_cast<range_size_t<C>>(ranges::size(r))); ranges::copyfor_each(r, container-inserterappend<range_reference_t<R>>(c));