3

I want to use macros to create my source code simpler

This is my code

constexpr auto make_index_sequence_array(size_t i ,std::index_sequence<arg...>) {
    return std::array<size_t, sizeof...(arg)> {i+arg...};
}
#define RANGE(start , end) make_index_sequence_array(start,std::make_index_sequence<end-start>{})
#define ZeroTo(end) RANGE(0 , end)
#define Repeat(end) for(auto itr : RANGE(0 , end))

void main() {
    vector<int> a = { 1,2,3 };
    for (auto row : RANGE(0,a.size()))
        cout << std::setw(4) << a[row];
    cout << '\n';
}

I know I can use :

void main() {
    vector<int> a = { 1,2,3 };
    for (auto itr: a)
        cout << std::setw(4) << itr;
    cout << '\n';
}

But it is a simple example and I want to use this style in more situations. The error while compiling is:

Error C2975 '_Size': invalid template argument for 'std::make_index_sequence', expected compile-time constant expression

How can I use my macros? Or even is it possible?

Jonas
  • 6,915
  • 8
  • 35
  • 53
Sam Mokari
  • 461
  • 3
  • 11

1 Answers1

2

My recommendation is that you use iterators, I wrote an example below. Something like this would do it in C++ < C++17:

#include <iostream>

template <class T>
struct RangeIter {
    RangeIter(T from, T to, T curr ) :
    _from(from), _to(to), _curr(curr) {
    }

    T operator*() const { 
      return _curr;
    }

    T operator++() {
      ++_curr;
      return _curr;
    }

    bool operator==(const RangeIter & other) {
      assert(_from == other._from && _to == other._to);
      return _curr == other._curr;
    }

    bool operator!=(const RangeIter & other) {
      return !(_curr == other._curr);
    }
    T _from, _to, _curr;
  };

template <class T>
struct Range {
  Range(T from, T to) : _from(from), _to(to) {}

  RangeIter<T> begin() { return RangeIter<T>(_from, _to, _from); }
  RangeIter<T> end() { 
    return RangeIter<T>(_from, _to, _to); 
  }

  T _from, _to; 
};

template <class T>
Range<T> makeRange(T to, T from) {
  return Range<T>(to, from);
}

int main() {

    for (auto i : makeRange(0, 10)) {
       std::cout << i << std::endl;
    }
}

For C++17 you can use different types for the begin and end iterator and improve on this. You can use sentinels. You could take a look here: How the new range-based for loop in C++17 helps Ranges TS?

A C++-17 only solution here:

#include <iostream>


template <class T>
struct RangeSentinel {
   RangeSentinel(T stopVal) : _stopVal(stopVal) {}

   T _stopVal;
};

template <class T>
struct RangeIter {
    RangeIter(T from, T to, T curr) :
    _from(from), _to(to), _curr(curr) {
    }

    T operator*() const { 
      return _curr;
    }

    T operator++() {
      ++_curr;
      return _curr;
    }

    bool operator==(const RangeSentinel<T> & other) {
      assert(_from == other._from && _to == other._to);
      return _curr == other._stopVal;
    }

    bool operator!=(const RangeSentinel<T> & other) {
      return !(_curr == other._stopVal);
    }
    T _from, _to, _curr;
  };



template <class T>
struct Range {
  Range(T from, T to) : _from(from), _to(to) {}

  RangeIter<T> begin() { return RangeIter<T>(_from, _to, _from); }
  RangeSentinel<T> end() { 
    return RangeSentinel<T>(_to); 
  }

  T _from, _to; 
};

template <class T>
Range<T> makeRange(T to, T from) {
  return Range<T>(to, from);
}

int main() {

    for (auto i : makeRange(0, 10)) {
       std::cout << i << std::endl;
    }
}

As you can see, in the C++17 solution I do not need to store again _from and _to variables, since the sentinel is a different type.

Community
  • 1
  • 1
Germán Diago
  • 7,473
  • 1
  • 36
  • 59
  • check you Code for int main() { for (auto i : makeRange(2, 11)) { std::cout << i << std::endl; } getchar(); } It does not work correctly. – Sam Mokari Jan 23 '17 at 00:54
  • 1
    Thanks @SamMokari for the feedback. I think this does not change the gist of what I am trying to illustrate. I am not doing homework, I am giving direction. :) I think you could adapt it reasonably starting from there. – Germán Diago Jan 23 '17 at 04:18