constexpr in for-Statement

时间:2018-02-21 18:34:06

标签: c++ for-loop c++17 template-meta-programming if-constexpr

提供了if constexpr,其中包含:

  

condition的值必须是类型为getpid的上下文转换的常量表达式。如果值为bool,则丢弃statement-false(如果存在),否则将丢弃statement-true

有没有办法在true语句中使用它?要在编译时展开循环吗?我希望能够做到这样的事情:

for

3 个答案:

答案 0 :(得分:6)

  

有没有办法在for语句中使用它?要在编译时展开循环吗?我希望能够做这样的事情

我不会以这么简单的方式思考。

但是如果你能负担一个帮助函数,std::integer_sequence和一个未使用的C风格整数数组的初始化,从C ++ 14开始你可以做如下的事情

#include <utility>
#include <iostream>

template <int ... Is>
void foo_helper (std::integer_sequence<int, Is...> const &)
 {
   using unused = int[];

   (void)unused { 0, (std::cout << Is << std::endl, 0)... };
 }

template <int T>
void foo ()
 { foo_helper(std::make_integer_sequence<int, T>{}); }

int main ()
 {
   foo<42>();
 }

如果您可以使用C ++ 17,则可以避免使用unused数组,并且使用折叠,foo_helper()可以简单地编写如下

template <int ... Is>
void foo_helper (std::integer_sequence<int, Is...> const &)
 { ((std::cout << Is << std::endl), ...); }

答案 1 :(得分:4)

如果编译器知道循环限制,编译器将展开循环,如果它发现它有益。并非所有循环展开都是有益的!对于循环展开的好处,你不太可能比编译器做出更好的决定。

不需要constexpr for(正如你所说的那样),因为constexpr if是启用功能 - 你可能会在constexpr if假分支内放置会导致程序格式错误的代码 - 这不是纯粹的优化。

另一方面,

Constexpr for将是纯粹的优化(至少在您描述时,不计算循环执行0次的边缘情况),因此最好留给'as-if'优化规则。

答案 2 :(得分:2)

不是没有帮助代码。

#define RETURNS(...) \
  noexcept(noexcept(__VA_ARGS__)) \
  -> decltype(__VA_ARGS__) \
  { return __VA_ARGS__; }

template<std::size_t I>
using index_t = std::integral_constant<std::size_t, I>;

template<std::size_t...Is>
constexpr auto index_over( std::index_sequence<Is...> ) noexcept(true) {
  return [](auto&& f)
    RETURNS( decltype(f)(f)( index_t<Is>{}... ) );
}
template<std::size_t N>
constexpr auto index_upto( index_t<N> ={} ) noexcept(true) {
  return index_over( std::make_index_sequence<N>{} );
}

template<class F>
constexpr auto foreacher( F&& f ) {
  return [&f](auto&&...args) noexcept( noexcept(f(args))&&... ) {
    ((void)(f(args)),...);
  };
}

这是我们的管道。

template<int T>
void foo() {
  index_upto<T>()(
    foreacher([](auto I){
      std::cout << I << "\n";
    })
  );
}

每个步骤都有值的编译时循环。

或者我们可以隐藏细节:

template<std::size_t start, std::size_t length, std::size_t step=1, class F>
constexpr void for_each( F&& f, index_t<start> ={}, index_t<length> ={}, index_t<step> ={} ) {
  index_upto<length/step>()(
    foreacher([&](auto I){
      f( index_t<(I*step)+start>{} );
    })
  );
}
然后我们得到:

for_each<0, T>([](auto I) {
  std::cout << I << "\n";
});

for_each([](auto I) {
  std::cout << I << "\n";
}, index_t<0>{}, index_t<T>{});

这可以通过用户定义的文字和模板变量进一步改进:

template<std::size_t I>
constexpr index_t<I> index{};

template<char...cs>
constexpr auto operator""_idx() {
  return index< parse_value(cs...) >;
}

其中parse_valueconstexpr函数,它接受char...序列并生成无符号整数表示。