This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.
Section: 27.10.11 [transform.inclusive.scan] Status: New Submitter: Agustín K-ballo Bergé Opened: 2020-07-07 Last modified: 2020-09-06
Priority: 3
View all issues with New status.
Discussion:
The requirements for the overloads of std::transform_inclusive_scan without an initial value incorrectly assume that the internal accumulator uses the iterator's value type, as it does for std::inclusive_scan, rather than the transformed type of the iterator's value type, as it was intended.
According to the standard, the following program is ill-formed as it requires std::string to be convertible to int:auto vs = {0, 1, 2}; std::transform_inclusive_scan( vs.begin(), vs.end(), std::ostream_iterator<std::string>(std::cout, ";"), [](std::string x, std::string y) { return x + y; }, [](int x) { return std::to_string(x); });
libstdc++ and Microsoft's STL accept the snippet, producing 0;01;012; as expected, libc++ strictly conforms to the standard and rejects it.
These constrains were introduced by P0574R1.[2020-07-17; Priority set to 3 in telecon]
Proposed resolution:
This wording is relative to N4861.
[Drafting note: Current implementations that accept the code, do some form of auto acc = unary_op(*first);, therefore the following proposed wording uses decay_t instead of e.g. remove_cvref_t.]
Modify 27.10.11 [transform.inclusive.scan] as indicated:
template<class InputIterator, class OutputIterator, class BinaryOperation, class UnaryOperation> constexpr OutputIterator transform_inclusive_scan(InputIterator first, InputIterator last, OutputIterator result, BinaryOperation binary_op, UnaryOperation unary_op); template<class ExecutionPolicy, class ForwardIterator1, class ForwardIterator2, class BinaryOperation, class UnaryOperation> ForwardIterator2 transform_inclusive_scan(ExecutionPolicy&& exec, ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result, BinaryOperation binary_op, UnaryOperation unary_op); template<class InputIterator, class OutputIterator, class BinaryOperation, class UnaryOperation, class T> constexpr OutputIterator transform_inclusive_scan(InputIterator first, InputIterator last, OutputIterator result, BinaryOperation binary_op, UnaryOperation unary_op, T init); template<class ExecutionPolicy, class ForwardIterator1, class ForwardIterator2, class BinaryOperation, class UnaryOperation, class T> ForwardIterator2 transform_inclusive_scan(ExecutionPolicy&& exec, ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result, BinaryOperation binary_op, UnaryOperation unary_op, T init);-1- Let U be
-2- […]the value type of decltype(first)decay_t<decltype(unary_op(*first))>.