如何创建用于创建循环的新样式?

时间:2017-01-19 23:04:35

标签: c++ c++11

我想使用宏来创建更简单的源代码

这是我的代码

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';
}

我知道我可以使用:

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

但这是一个简单的例子,我希望在更多情况下使用这种风格。 编译时的错误是:

  

错误C2975'_Size':'std :: make_index_sequence'的模板参数无效,预期编译时常量表达式

如何使用我的宏?或者甚至有可能吗?

1 个答案:

答案 0 :(得分:2)

我的建议是你使用迭代器,我在下面写了一个例子。像这样的东西可以在C ++&lt; 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;
    }
}

对于C ++ 17,您可以为begin和end迭代器使用不同的类型,并对此进行改进。你可以使用哨兵。你可以看看这里:How the new range-based for loop in C++17 helps Ranges TS?

这里只有C ++ - 17解决方案:

#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;
    }
}

正如您所看到的,在C ++ 17解决方案中,我不需要再次存储_from和_to变量,因为sentinel是一个不同的类型。