如何为循环c ++编写声明14

时间:2016-10-05 09:52:59

标签: c++ range c++17

有没有办法在C ++ 14中为循环编写声明式样式

for(int i = 0; i < 10; i+=2) {
    // ... some code
}

我发现最接近的是使用提升

for(auto i : irange(1,10,2)){
     // .... some code
}

是否有c ++ 14/17标准方法可以达到同样的效果?

我试着用std :: make_integer_sequence()作为一个可能的起点,但是不能很好地理解它进行。

2 个答案:

答案 0 :(得分:5)

没有一种标准的方法可以根据需要迭代数值范围。但是,C ++ 14允许您非常轻松地创建自己的实用程序。

方法一:数值范围

这是未经优化的快速黑客攻击示例:

template <typename T>
struct num_range_itr
{
    T _value, _step;

    num_range_itr(T value, T step) 
        : _value{value}, _step{step} 
    {
    }

    auto operator*() const { return _value; }
    auto operator++() { _value += _step; }

    auto operator==(const num_range_itr& rhs) const { return _value == rhs._value; }
    auto operator!=(const num_range_itr& rhs) const { return !(*this == rhs); }
};

template <typename T>
struct num_range
{
    T _start, _end, _step;

    num_range(T start, T end, T step) 
        : _start{start}, _end{end}, _step{step} 
    {
    }

    auto begin() const { return num_range_itr<T>{_start, _step}; }
    auto end() const { return num_range_itr<T>{_end, _step}; }
};

template <typename T>
auto make_range(T start, T end, T step = 1)
{
    return num_range<T>{start, end, step};
}

上面的代码可以按如下方式使用:

for(auto i : make_range(0, 10, 2))
{
    std::cout << i << " ";
}

// Prints: 0 2 4 6 8

方法二:高阶函数

这是未经优化的快速黑客攻击示例:

template <typename T, typename TF>
auto for_range(T start, T end, T step, TF f)
{
    for(auto i = start; i < end; i += step)
    {
        f(i);
    }

    return f;
}

上面的代码可以按如下方式使用:

for_range(0, 10, 2, [](auto i){ std::cout << i << " "; });

// Prints: 0 2 4 6 8

可以找到代码on wandbox

如果要在实际项目中使用这些实用程序,则需要仔细编写它们以便安全地支持多种类型,避免无意的签名/无符号转换,避免无效范围,并确保它们得到优化。

答案 1 :(得分:0)

std::integer_sequence仅在您知道编译时的大小时才会帮助您。我个人讨厌前C ++ 11 for循环。写下这样的东西很容易犯错:

for (int i = 0; i < n; ++i) 
  for (int j = 0; j < m; ++i) // very hard to spot

我使用的是我的小助手seq_t类,我相信你所需要的。请注意typename std::enable_if。这是为了确保它仅用于整数类型(int, uint8_t, long long等),但您不能将其用于doublefloat。您可以通过三种不同的方式使用它:

for (int i : seq(1, 10))    // [1, 10), step 1
for (int i : seq(1, 10, 2)) // [1, 10), step 2
for (int i : seq(10))       // [0, 10), step 1

这是我的代码:

#include <type_traits>

template<typename T,
         typename = typename std::enable_if<std::is_integral<T>::value>::type >
class seq_t
{
  T m_begin;
  T m_end;
  T m_step;

public:
  class iterator
  {
    T m_curr;
    T m_step;

    constexpr iterator(T curr, T step)
      : m_curr(curr), m_step(step)
    {
    }

    constexpr iterator(T end)
      : m_curr(end), m_step(0)
    {
    }

    friend class seq_t;

  public:
    constexpr iterator& operator++()
    {
      m_curr += m_step;
      return *this;
    }

    constexpr T operator*() const noexcept
    {
      return m_curr;
    }

    constexpr bool operator!=(const iterator& rhs) const noexcept
    {
      return this->m_curr != rhs.m_curr;
    }
  };

  constexpr iterator begin(void) const noexcept
  {
    return iterator(m_begin, m_step);
  }

  constexpr iterator end(void) const noexcept
  {
    return iterator(m_end, m_step);
  }

  constexpr seq_t(T begin, T end, T step) noexcept
    : m_begin(begin), m_end(end), m_step(step)
  {
  }
};

template<typename T>
inline seq_t<T>
constexpr seq(T begin, T end, T step = 1) noexcept
{
  return seq_t<T>(begin, end, step);
}

template<typename T>
inline seq_t<T>
constexpr seq(T end) noexcept
{
  return seq_t<T>(T{0}, end, 1);
}