【问题标题】:for constexpr in constexpr functions对于 constexpr 函数中的 constexpr
【发布时间】:2020-05-04 19:01:33
【问题描述】:

我正在编写一个 constexpr 函数,需要使用 constexpr。循环可以手动展开,但我发现代码很难看而且是多余的。

如何制作“constexpr for”?

我应该创建一个助手类吗?如果是这样,我将如何写这样的东西:

#define for_constexpr( TYPE, VAR, START, CONDITION, END_OP, BODY ) \
    for_constexpr_helper< \
        TYPE, START, // TYPE START = 0; \
        [ ]( TYPE VAR ) constexpr { return CONDITION; }, \
        [ ] constexpr { END_OP; }, \
        [ & ]( TYPE VAR ) constexpr { BODY; } >( )

用法类似于

int x = 0;
for_constexpr( int, i, 0, i < 3, ++i, x += i * 2 );

更具体地说,如何在 constexpr 上下文中使用i,例如模板参数?

我有什么选择?

示例代码:

auto ret = 0;
for ( int i = 0; i < 3; ++i )
{
    static_assert( i != 4 ); // just an example
    ret += i;
}
return ret;

这不是 constexpr。丑陋的例子:

auto ret = 0;
ret += 1;
ret += 2;
ret += 3;
return ret; // works

【问题讨论】:

  • 我不关注;你能举一个丑陋的手工版本的例子吗?
  • constexpr 函数已经可以使用 for 循环。你需要什么它没有给你?
  • @NathanOliver 使用i 作为模板参数;
  • @cigien 添加了一些示例代码

标签: c++ c++20


【解决方案1】:

我不会使用宏来执行此操作。如果您可以通过

“传递”循环变量
template <std::size_t i>
struct foo{
    constexpr void operator()() {
        static_assert(i != 3);
    }
};

即。将静态循环的主体放在operator() 中,然后您可以使用以下内容:

template<template <std::size_t> class F, std::size_t... I>
auto static_for_impl(std::index_sequence<I...>)
{
    (F<I>()(),...);
}


template<std::size_t N,template <std::size_t> class F,typename Indices = std::make_index_sequence<N>>
constexpr void static_for(){
    static_for_impl<F>(Indices{});
}

用法:

int main() {    
    static_for<5,foo>();    
}

Live Example

或者,您可以使用std::integral_constant&lt;std::size_t, N&gt; 作为参数,这样它就可以与 lambdas 一起使用并且不需要编写类模板(感谢 @Artyer):

#include <cstddef>
#include <utility>

template<typename F, std::size_t... I>
auto static_for_impl(F&& f, std::index_sequence<I...>) {
    (static_cast<void>(f(std::integral_constant<std::size_t, I>{})), ...);
}

template<std::size_t N, typename F>
constexpr void static_for(F&& f) {
    static_for_impl<F>(std::forward<F>(f), std::make_index_sequence<N>{});
}

int main() {
    static_for<5>([](auto i) {
        static_assert(i != 5);
    });
}

Live Example

在 C++20 中,您可以使用模板 lambda(感谢 @Jarod42):

#include <functional>
#include <utility>

template<std::size_t N, typename F>
constexpr void static_for(F&& f) {
    [&f]<std::size_t...Is>(std::index_sequence<Is...>){
        (static_cast<void>(f(std::integral_constant<std::size_t, Is>{})), ...);
     }(std::make_index_sequence<N>{});
}

int main() {
    static_for<5>([](auto i) {
        static_assert(i != 5);
    });
}

Live Example

【讨论】:

  • 或者使用 std::integral_constant&lt;std::size_t, N&gt; 参数调用,这样你就可以使用 lambdas 而不是模板类:godbolt.org/z/Ezw8tQ
  • @Artyer 啊,不错。这就是我想要的,但我不知道如何到达那里。我会将其添加到答案中,但仅限于明天
  • @Artyer: Demo 使用 C++20 模板 lambda。
  • @Jarod42 希望您不介意我将您的代码添加到答案中
  • @Artyer 我将您的代码添加到了答案中。它比我的原版要好得多,但我还是把它留下来只是为了展示不同的方式。我可以想象需要类模板并不是真正的限制的情况
猜你喜欢
  • 2021-04-20
  • 1970-01-01
  • 2020-10-08
  • 1970-01-01
  • 1970-01-01
  • 2015-05-22
  • 2018-07-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多