首页 > 解决方案 > 对于 constexpr 函数中的 constexpr

问题描述

我正在编写一个 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 );

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

我有哪些选择?

示例代码:

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

标签: c++c++20

解决方案


我不会使用宏来做到这一点。如果您可以通过“传递”循环变量

template <std::size_t i>
struct foo{
    constexpr void operator()() {
        static_assert(i != 3);
    }
};

IE。把你的静态循环的主体放在里面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>();    
}

现场示例

或者,您可以将std::integral_constant<std::size_t, N>其用作参数,以便它与 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);
    });
}

现场示例

在 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);
    });
}

现场示例


推荐阅读