Date: Thu, 29 Aug 2019 13:48:05 -0400
On 29/08/2019 10.39, Arthur O'Dwyer via Std-Proposals wrote:
> On Thu, Aug 29, 2019 at 9:51 AM Matthew Woehlke via Std-Proposals wrote:
>> I wonder if instead we could make this work?
>>
>> int x = ...;
>> for (auto const i : std::indices(x)) // i → int
>> ;
>> for (auto const i : std::indices<size_t>(x)) // i → size_t
>> ;
>
> Easy ways to do that would be:
>
> template<class T> T indices(T max); // indices<int>(UINT_MAX) begins by
> implicitly converting UINT_MAX to int
This would trigger a warning, though. We don't want that.
> or:
>
> template<class R, class T> R indices_impl(T max); //
> indices_impl<int>(UINT_MAX) never converts UINT_MAX to int
>
> template<class R = void, class T>
> auto indices(T max) {
> if constexpr (std::is_void_v<R>) {
> return indices_impl<T>(max);
> } else {
> return indices_impl<R>(max);
> }
> }
Yes, I think that works :-). (I'd argue you are missing a static_cast,
but that's implementation details.)
I like this, because it is explicit about what type you want out, if you
care, and otherwise uses the same as the type in.
> Incidentally, there has been some discussion yesterday in the #ranges Slack
> channel about the fact that
> - std::iota(0, 10) compiles fine, producing a sized range
> - std::iota(0, 10u) does not compile
> - std::iota(0, 10.0f) compiles fine, producing an unsized range
> - std::iota(short(0), 65536) compiles fine, producing an unsized and
> infinite range
>
> In short: implicit conversions are the devil and should be avoided in good
> APIs.
Yeah... the current operation of iota, taking the type from the first
argument (which is almost always the literal "0"), is an issue :-).
That reminds me, though... what is wrong with:
for (auto const i : std::iota(x))
...? (IOW, add a single-argument overload that counts from 0 up to the
argument?)
> On Thu, Aug 29, 2019 at 9:51 AM Matthew Woehlke via Std-Proposals wrote:
>> I wonder if instead we could make this work?
>>
>> int x = ...;
>> for (auto const i : std::indices(x)) // i → int
>> ;
>> for (auto const i : std::indices<size_t>(x)) // i → size_t
>> ;
>
> Easy ways to do that would be:
>
> template<class T> T indices(T max); // indices<int>(UINT_MAX) begins by
> implicitly converting UINT_MAX to int
This would trigger a warning, though. We don't want that.
> or:
>
> template<class R, class T> R indices_impl(T max); //
> indices_impl<int>(UINT_MAX) never converts UINT_MAX to int
>
> template<class R = void, class T>
> auto indices(T max) {
> if constexpr (std::is_void_v<R>) {
> return indices_impl<T>(max);
> } else {
> return indices_impl<R>(max);
> }
> }
Yes, I think that works :-). (I'd argue you are missing a static_cast,
but that's implementation details.)
I like this, because it is explicit about what type you want out, if you
care, and otherwise uses the same as the type in.
> Incidentally, there has been some discussion yesterday in the #ranges Slack
> channel about the fact that
> - std::iota(0, 10) compiles fine, producing a sized range
> - std::iota(0, 10u) does not compile
> - std::iota(0, 10.0f) compiles fine, producing an unsized range
> - std::iota(short(0), 65536) compiles fine, producing an unsized and
> infinite range
>
> In short: implicit conversions are the devil and should be avoided in good
> APIs.
Yeah... the current operation of iota, taking the type from the first
argument (which is almost always the literal "0"), is an issue :-).
That reminds me, though... what is wrong with:
for (auto const i : std::iota(x))
...? (IOW, add a single-argument overload that counts from 0 up to the
argument?)
-- Matthew
Received on 2019-08-29 12:50:10