如何使用模板元编程展开for循环

时间:2017-10-22 06:04:12

标签: c++ for-loop template-meta-programming

如何编写一个简单的C ++代码来简单地运行具有特定展开因子的for循环? 例如,我需要编写一个for循环,为数组的每个索引赋值i,即A [i] = i表示数组大小,比如1e6。

现在我想添加一个展开因子,比如说20.我不想手动编写20行代码并重复5k次。我该怎么做呢?我是否嵌套我的for循环?如果我使用模板元编程,编译器会自动为我做一些展开吗?如何手动设置展开因子(在编译时固定)?

1 个答案:

答案 0 :(得分:2)

以下示例是用 C ++ 17 编写的,但是有一些更详细的技术,这个想法适用于C ++ 11及更高版本。

如果你真的想强制进行一些展开,你可以考虑将lambda传递给这样的模板化函数:

template<auto i, auto N, auto delta, class F>
constexpr void loop(From<i>, Less<N>, By<delta>, F f) noexcept {
  if constexpr(i<N) {
    f(Val<i>{});
    loop(from<i+delta>, less<N>, by<delta>, f);
  }
}

要使用它,您可以编写类似

的代码
loop(from<100>, to<200>, by<5>, [&] (auto i) {
  std::cout << "do something with " << i << std::endl;
});

完整working example(在应用之前考虑):

#include <iostream>

namespace Loop {

template<auto v> using Val = std::integral_constant<decltype(v), v>;

template<auto i> struct From : Val<i> {};
template<auto i> static constexpr From<i> from{};

template<auto i> struct Less : Val<i> {};
template<auto i> static constexpr Less<i> less{};

// `to<i>` implies `less<i+1>`
template<auto i> struct To : Less<i+decltype(i)(1)> {};
template<auto i> static constexpr To<i> to{};

template<auto i> struct By : Val<i> {};
template<auto i> static constexpr By<i> by{};

template<auto i, auto N, auto delta, class F>
constexpr void loop(From<i>, Less<N>, By<delta>, F f) noexcept {
  if constexpr(i<N) {
    f(Val<i>{});
    loop(from<i+delta>, less<N>, by<delta>, f);
  }
}

// overload with two arguments (defaulting `by<1>`)
template<auto i, auto N, class F>
constexpr void loop(From<i>, Less<N>, F f) noexcept {
  loop(from<i>, less<N>, by<decltype(i)(1)>, f);
}

// overload with two arguments (defaulting `from<0>`)
template<auto N, auto delta, class F>
constexpr void loop(Less<N>, By<delta>, F f) noexcept {
  loop(from<decltype(N)(0)>, less<N>, by<delta>, f);
}

// overload with one argument (defaulting `from<0>`, `by<1>`)
template<auto N, class F>
constexpr void loop(Less<N>, F f) noexcept {
  using Ind = decltype(N);
  loop(from<Ind(0)>, less<N>, by<Ind(1)>, f);
}

} // namespace Loop

int main() {
  {
    using namespace Loop;
    loop(from<100>, to<200>, by<5>, [&] (auto i) {
      constexpr int it_is_even_constexpr = i;
      std::cout << it_is_even_constexpr << std::endl;
    });
  }

  return 0;
}