如何编写循环声明 C++14
How to write a declarative for loop c++14
有没有办法在 C++14 中为循环编写声明式样式
for(int i = 0; i < 10; i+=2) {
// ... some code
}
我发现最接近的是使用 boost 是
for(auto i : irange(1,10,2)){
// .... some code
}
是否有实现相同效果的 c++14/17 标准方法?
我尝试将 std::make_integer_sequence() 作为可能的起点,但无法想明白了。
没有一种标准方法可以按照您的需要在数值范围内进行迭代。然而,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。
如果你想在实际项目中使用这些实用程序,你需要仔细编写它们以安全地支持多种类型,避免无意的 signed/unsigned 转换,避免无效范围,并确保它们得到优化.
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_tclass,相信正是你所需要的。请注意 typename std::enable_if
。这是为了确保它只用于整数类型(int, uint8_t, long long
等),但不能用于 double
或 float
。您可以通过三种不同的方式使用它:
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);
}
有没有办法在 C++14 中为循环编写声明式样式
for(int i = 0; i < 10; i+=2) {
// ... some code
}
我发现最接近的是使用 boost 是
for(auto i : irange(1,10,2)){
// .... some code
}
是否有实现相同效果的 c++14/17 标准方法?
我尝试将 std::make_integer_sequence() 作为可能的起点,但无法想明白了。
没有一种标准方法可以按照您的需要在数值范围内进行迭代。然而,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。
如果你想在实际项目中使用这些实用程序,你需要仔细编写它们以安全地支持多种类型,避免无意的 signed/unsigned 转换,避免无效范围,并确保它们得到优化.
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_tclass,相信正是你所需要的。请注意 typename std::enable_if
。这是为了确保它只用于整数类型(int, uint8_t, long long
等),但不能用于 double
或 float
。您可以通过三种不同的方式使用它:
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);
}