8

提供if constexpr,其中:

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

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

template <int T>
void foo() {
   for constexpr (auto i = 0; i < T; ++i) cout << i << endl;
}
4

3 回答 3

9

有没有办法在 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), ...); }
于 2018-02-21T18:57:12.110 回答
6

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

不需要constexpr for(如您所说),因为constexpr if启用功能-您可以将会使程序格式错误的代码放入constexpr if错误分支中-这不是纯粹的优化。

Constexpr for另一方面,这将是纯粹的优化(至少正如您所描述的那样,不计算循环执行 0 次的边缘情况),因此最好留给“as-if”优化规则。

于 2018-02-21T18:54:53.070 回答
3

不是没有帮助代码。

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

whereparse_value是一个constexpr函数,它接受一个序列char...并产生它的无符号整数表示。

于 2018-02-21T19:51:31.577 回答