Wednesday, January 21, 2015

Comment on Reader Q&A: auto and for loop index variables by Enrico

 

Comment on Reader Q&A: auto and for loop index variables by Matthew

How about:
    auto mySize = someObject.size(), i = mySize;    for (i = 0; i < mySize; i++) { }  

Read More »

Comment on Reader Q&A: auto and for loop index variables by John Smith

I believe range-for is still the solution here. I’ll use boost::irange here, but you can roll your own simple wrapper for this quite easily:
  #include <boost/range/irange.hpp>  // ...  template<typename T, typename U, typename V = int>  inline decltype(auto) range(T a, U b, V s = 1) {    using D = decltype(true ? a : b);     return boost::irange<D>(a, b, s);  }  // ...  void g(...);  // ...   auto f(std::vector<int> const& v) {    for(auto&& i : range(0, v.size())) {      g(i);    }  }  
This lets the usual integer type promotion machinery of C++ do its thing (which, depending how you see it, can be a good or bad thing—but it’s predictable at least).

Read More »

Comment on Reader Q&A: auto and for loop index variables by Juan Carlos Arevalo Baeza

The obvious ideal (IMHO) is to allow range-for with ranges of values instead of iterators. I don’t know if the ranges proposals or discussions are contemplating this. So for instance, this would be something like:
  for (auto i : range_from_to{0, mySize-1})  {      ... use i as an index ...  }  
Names are, of course, up for grabs. This is implementable today. range_from_to “just” needs to return something that resembles input iterators (that implements the input iterator interface) when begin() and end() are called. The devil being potentially in the details (in the implementation of the end() sentinels and comparison operators, really).
With this in the standard library, classic for-loops should be relegated to one-time situations where we don’t have a range readily available, as it’d be more cumbersome to implement the range than to just use the raw loop.
JCAB

Read More »

Comment on Reader Q&A: auto and for loop index variables by stackedcrooked

I sometimes use
auto i = 0ul;
.

Read More »

Comment on Reader Q&A: auto and for loop index variables by enerjazzer

I think a simple counting range would get the best of the two worlds:
for ( auto i: count_until(mySize) ) ...
(assuming the compiler can optimize this as efficiently as plain for loop)
Implementation of such a range is trivial and left as an exercise for a reader :)

Read More »

Comment on Reader Q&A: auto and for loop index variables by Herb Sutter

Great points on the index-range examples. We do need an iterable ‘range of values’ in the standard library, but you can roll your own in the several ways suggested in the meantime.

Read More »

Comment on Reader Q&A: auto and for loop index variables by FJW

      for ( auto i: count_until(mySize) ) ...  
Is indeed the way to go; aside from that though, we still need a (preferably core-language) integer-literal for std::size_t (also for the std::[u]int*_t-typedefs). It is really very sad that there is no simpler way of generating a zero of those types than writing out something like std::size_t{}.
std::size_t is certainly one of the most often needed integer-types, but people still access containers with ints because they are so much more convenient to type. This is really a terrible situation.

Read More »

Comment on Reader Q&A: auto and for loop index variables by Jon

@Herb, I was wondering if you agree with these statements:
1) “Using an unsigned instead of an int to gain one more bit to represent positive integers is almost never a good idea.” (Stroustrup)
2) Implicit conversion rules make unsigned types into bug attractors (http://stackoverflow.com/a/10168569/297451)
Eg: size_t x = 0; for(size_t i=10; i>=x; –i) {}
If so, is it reasonable to cast away the unsigned-ness with a static_cast or boost::numeric_cast?

Read More »

Comment on Reader Q&A: auto and for loop index variables by bames53

‘Generic’ code is good not just for templates, but also for portable code, where different platforms may define things differently. So in non-template code you might need `0` to avoid warnings on one platform and `0u` to avoid them on another.
Needing indexes and values seems common enough that perhaps their should be a special syntax for it.
Failing that perhaps a standard algorithm: `for_each(Range &&r, Functor &&f)` where the functor can optional accept both an index and the elements.
And one maybe-improvement over the options presented here: `for (auto size = v.size(), i = 0*size; i < size; ++i) {`

Read More »

Comment on Reader Q&A: auto and for loop index variables by bames53

@Juan Carlos Arevalo Baeza
Using range-v3 (and a range compatible range-for-loop) your idea looks like:
for (auto i : ranges::view::iota(0, size-1))
I guess we can also get indexes and values together:
for (auto i_v : ranges::view::zip(ranges::view::iota(0), v))
std::cout << "Index: " << std::get(*i) << " Value: " << std::get(*i) << '\n';

Read More »

Comment on Reader Q&A: auto and for loop index variables by Patrice Roy

How about something like this? It’s a back-of-the-envelope solution, and I haven’t given more than a few seconds to the naming of it all, but it works for the obvious cases (I have not done anything that remotely looks like real testing, and it’s a bit late here):
  #include <iostream>  #include <vector>  #include <algorithm>  #include <iterator>  using namespace std;    template <class C>     auto size(const C &cont) -> decltype(cont.size())     {        return cont.size();     }  template <class C, std::size_t N>     std::size_t size(const C (&arr)[N])     {        return N;     }    template <class T>     class value_range        : public std::iterator<std::bidirectional_iterator_tag, T>     {        T first, last;     public:        template <class U>           class value_iterator           {              U cur;           public:              value_iterator(U init)                 : cur{init}              {              }              value_iterator& operator++()              {                 ++cur;                 return *this;              }              value_iterator operator++(int)              {                 auto temp { *this };                 operator++();                 return temp;              }              value_iterator& operator--()              {                 --cur;                 return *this;              }              value_iterator operator--(int)              {                 auto temp{ *this };                 operator--();                 return temp;              }              bool operator==(const value_iterator &other) const              {                 return cur == other.cur;              }              bool operator!=(const value_iterator &other) const              {                 return !(*this == other);              }              U operator*()              {                 return cur;              }              U operator*() const              {                 return cur;              }           };        using iterator = value_iterator<T>;        using const_iterator = value_iterator<T>;        value_range(T first, T last)           : first{ first }, last{ last }        {        }        iterator begin() { return first; }        iterator end() { return last; }        const_iterator begin() const { return first; }        const_iterator end() const { return last; }        const_iterator cbegin() const { return first; }        const_iterator cend() const { return last; }     };    template <class C>     auto value_range_from(C &cont) -> value_range<decltype(size(cont))>     {        return value_range<decltype(size(cont))>{ 0, size(cont) };     }    int main()  {     int arr[] = { 2, 3, 5, 7, 11 };     vector<int> v(begin(arr), end(arr));     for (const auto &val : arr)        cout << val << ' ';     cout << '\n';     for (const auto &val : v)        cout << val << ' ';     cout << '\n';     for (auto i : value_range_from(arr))        cout << "arr[" << i << "] == " << arr[i] << "; ";     cout << '\n';     for (auto i : value_range_from(v))        cout << "v[" << i << "] == " << v[i] << "; ";     cout << '\n';  }    

Read More »

Comment on Reader Q&A: auto and for loop index variables by Gevorg Voskanyan

Here’s an idea off the top of my head:
  template < typename C >  auto begin_index( const C &c ) -> decltype( c.size() )  {   return 0;  }    template < typename T >  void f( const std::vector< T > &v )  {   for ( auto i = begin_index( v ); i < v.size(); ++i ) { ... }     // if C++17 brings us std::size(), then this will look more elegant:   for ( auto i = begin_index( v ); i < size( v ); ++i ) { ... }  }  

Read More »

Comment on Reader Q&A: auto and for loop index variables by rhalbersma

I proposed the “z” literal suffix for size_t variables (see N4254 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4254.html) so that one can write “auto s = 0z; // s has type size_t”

Read More »

Comment on Reader Q&A: auto and for loop index variables by max0x7ba

I sometimes do reverse loops for this reason:
  for(auto i = v.size(); i--;)  

Read More »

Comment on Reader Q&A: auto and for loop index variables by Marco Arena

Guys, what about performance of
  for (auto i : ranges::view::iota(0, size-1))  
compared to the simpler:
  for (auto i=0; i<size; i++)  
?
Is the compiler still able to optimize/vectorize? I’m asking because I don’t know and I’m sure some of you do.
Thanks!
Marco

Read More »

Comment on Reader Q&A: auto and for loop index variables by evincarofautumn

The fact that some programmers may not be familiar with a language feature is not a reason to avoid it, particularly if it makes the code more correct! decltype is fine here, and you can write it even more neatly than the original:
for (decltype(someObject.size()) i = 0; i < someObject.size(); i++) { … }
All these answers suggesting ranges are great, but even farther afield and less searchable than decltype.

Read More »

Comment on Reader Q&A: auto and for loop index variables by rhalbersma

In N4254 I proposed the “z” suffix for size_t literals:
auto s = 0z; // s has type size_t
This allows code like this:
  #include <cstddef>  #include <vector>  using namespace std::support_literals;    int main()  {    auto v = std::vector<int> { 98, 03, 11, 14, 17 };    for (auto i = 0z, s = v.size(); i < s; ++i) {       /* use both i and v[i] */     }  }  

Read More »

Comment on Reader Q&A: auto and for loop index variables by Elliot Goodrich

I wrote a interval arithmetic library (https://github.com/elliotgoodrich/EZInterval) that allows iterating over intervals. The ez::make_interval variable has overloaded operator[] and operator() to let you choose whether the interval is open or closed.
// prints 012345  for(auto i : ez::make_interval[0][5])      std::cout << i;    // prints 01234 (  for(auto i : ez::make_interval[0](5))      std::cout << i;    // prints 12345  for(auto i : ez::make_interval(0)[5])      std::cout << i;    // prints 1234  for(auto i : ez::make_interval(0)(5))      std::cout << i;
This works with any other type that acts like a numeric type, e,g pointers and iterators
std::vector<int> v = {1, 11, 21, 1112, 3112, 132112};    // prints "1 11 21 1112 3112 132112 "  for(std::vector<int>::iterator it : ez::make_interval[v.begin()](v.end()))      std::cout << *it << " ";
I’ve made a change and will commit later so that the type of i in the examples above will be the std::common_type of the lower and upper bound variables so ez::make_interval[0](size) will give you back a type of std::size_t when you iterate over it.

Read More »

Comment on Reader Q&A: auto and for loop index variables by marcmutz

(please excuse the spam, there’s no preview for comments…)
The 0*-trick only works if decltype(std::declval<int>() * std::declval<decltype(someObject.size())>()) is the same as decltype(someObject.size()).
This is the case for int, uint, size_t and ssize_t, but not for “smaller” types, such as short or uchar, because they’re promoted to int for any arithmetic. That also rules out xor and subtracting the size form itself to create a 0 value.
In generic code, what’s wrong with plain old (for a certain definition of “old”)
  for ( auto end = someObject.size(), i = decltype(end)(0); i != end; ++i)  
?

Read More »

Comment on Reader Q&A: auto and for loop index variables by TonyB

similar to Herb’s solution, but without a multiplication in sight: for( auto i = mySize – mySize; …

Read More »

Comment on Reader Q&A: auto and for loop index variables by red1939

As it was mentioned earlier: writing irange(end), irange(begin, end) and irange(begin, end, step) range wrappers (returning iterators) is simple to write yourself and from what I’ve checked even Visual Studio (which many times failed to optimize enough) and the performance (and assembly for anyone wondering) is the same as for regular for but you get terse syntax.

Read More »

Comment on Reader Q&A: auto and for loop index variables by Etheria

To be honest, I just use
for (size_t i = 0; i < v.size(); i++)
We can talk all we want about ranges. Sure, they would be nice, but we don’t have them yet, and especially for newbies, are we going to recommend a 3rd party library or writing our own solution for something so trivial? Just use size_t. It’s what the standard library uses, and so good practice IMO should be to use size_t (or a lesser unsigned type) for the size for your own classes.
It work seamlessly with the standard library and it should work with most 3rd party libraries and/or your own classes without signed/unsigned warnings and/or narrowing warnings.

Read More »

Comment on Reader Q&A: auto and for loop index variables by Riccardo

It’s actually a very interesting topic. I see a lot of unsigned/signed mismatches from static analysis tools due to these situations.
I currently favour:
for (decltype(someObject.size()) i = 0; i < someObject.size(); i++) { … }
I hope in the near future to be able to use non-member std::size() which is more generic as it works with built-in arrays too:
for (decltype(std::size(someObject)) i = 0; i < std::size(someObject); i++) { … }

Read More »

Comment on Reader Q&A: auto and for loop index variables by wokste

I have seen many suggestions for ranges and I like them. However, I would like to be able to quickly construct ranges for certain data structures:
  for (auto i : someContainer.range()){    ... use i as an index ...}  
I personally do not know if this is feasable, but I just look how the API would be the cleanest. In general, this .range() function should only be available for data structures with simple integer domain for keys.

Read More »

Comment on Reader Q&A: auto and for loop index variables by Enrico

Sorry, one function was missing:
  template <typename T>  static inline constexpr auto null(T&&) noexcept(noexcept(null<T>())) {      return null<T>();  }  

Read More »

Comment on Reader Q&A: auto and for loop index variables by Enrico

I also like the ‘range of values’ approach because it enforces code locality as the iteration boundaries are tied together and it is also very succinct.
As for the “null of a certain index type” problem we have some handy functions in our code base that merely call the default constructor (if any) and is basically syntactic sugar for the decltype(mySize){} approach, but clearly states the intent of the caller:
  template <typename T>  using remove_cv_ref_t = std::remove_const_t<std::remove_reference_t<T>>;    template <typename T>  using has_nothrow_default = std::is_nothrow_default_constructible<remove_cv_ref_t<T>>;    template <typename T>  static inline constexpr remove_cv_ref_t<T>  null() noexcept(has_nothrow_default<T>{}()) {      static_assert(std::is_default_constructible<remove_cv_ref_t<T>>{}(),                    "type must be default constructible to generate null object!");      return {};  }  
to be used like this:
  constexpr std::size_t sizeBuffer = 64;  for (auto i = null(sizeBuffer); i < sizeBuffer; ++i) {      static_assert(std::is_same<decltype(i), std::size_t>::value, "???");      // ...  }    constexpr std::uint8_t numElems = 64;  for (auto i = null(numElems); i < numElems; ++i) {      static_assert(std::is_same<decltype(i), std::uint8_t>::value, "???");      // ...  }  

Read More »
 

No comments:

Post a Comment