On 11/26/2017 10:28 PM, Vir Campestris wrote:
> On 26/11/2017 06:50, Gareth Owen wrote:
>> How do you feel about using it for loop variables:
>>
>> for(auto it = foo.begin(); it foo.end(); ++i) {}
>
> Is that an iterator or a const_iterator?
Explicitly writing out the iterator type can be verbose and brittle, and
so I wouldn't do that, but the question of how to communicate the
constness of the iterator's referent is interesting.
Well it wouldn't be interesting if the iterator referent constness was
always apparent from the constness of the collection. But e.g. with a
`std::set` the iterator referent (set item) is `const` regardless of the
constness of the set itself. And the other way, a `const` collection
producing iterators with non-`const` referents, can also, at least in
principle, occur, e.g. when the collection is a begin/end-pair proxy for
accessing items of some other collection.
When the loop can be expressed as a range based loop one can easily
communicate and enforce constness of the items:
for( auto const& item : foo ) //...
The other way can also easily be communicated,
for( auto& mutable_item : foo )
… but not so easily enforced:
for( auto& mutable_item : foo )
{
static_assert( not is_const_v<remove_reference_t<decltype(
mutable_item )>> );
//...
}
To help with enforcement one may therefore define e.g.
template< class Type >
void assert_is_mutable( Type& )
{
static_assert( not is_const_v<Type>, "The object must be
mutable" );
}
… and then write
for( auto& item : foo )
{
assert_is_mutable( item );
//...
}
The last approach works also for the original problem, by defining
template< class Type >
void assert_is_const( Type& )
{
static_assert( is_const_v<Type>, "The object must const" );
}
… and then writing
for( auto it = foo.begin(); it != foo.end(); ++it )
{
assert_is_const( *it );
//...
}
Doing this instead as expressions fed to `static_assert` runs into
problems. I think it would be nice if a call of a `constexpr` function F
with an actual argument that involved a call of a non-`constexpr`
function, could yield a `constexpr` result when only the type of the
actual argument was used to produce the result (or perhaps simpler, if
the formal argument in F was not named). This could solve :-) also the
problem with C++17 `std::size`, which can't formally be applied to a
formal argument array reference, which IMHO is just über-silly.
>> or
>>
>> for(const auto& x : xvec) {}
>
> There's no need to do it here either.
>
> The problem in the absence of really clever tools (1)(2) is that the
> casual reader can't tell at a glance what x really is. And even when the
> tools are working you usually have to "hover" on the variable, then
> wait, to see. Which is slower.
Much of the point is that one really doesn't care about the exact type
of an iterator, and that it's desirable to /not/ know, because using
that knowledge just makes the code brittle and possibly non-portable.
> [snip]
> 2) I don't always agree with Herb. Nearly always, but not every time!
NAAAH - Nearly Almost Always Auto, Herb.
Cheers!,
- Alf