для constexpr в функциях constexpr - PullRequest
1 голос
/ 04 мая 2020

Я пишу функцию constexpr, и мне нужно использовать constexpr для. L oop может быть вручную расширен вручную, но я нахожу это уродливым в коде и избыточным.

Как я могу создать "constexpr for"?

Должен ли я сделать вспомогательный класс ? Если да, то как бы я go написал что-то вроде этого:

#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

1 Ответ

0 голосов
/ 04 мая 2020

Я бы не использовал макросы для этого. Если вас устраивает «передача» переменной l oop через

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

Ie. поместите тело вашей стати c l oop в 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<std::size_t, N> в качестве аргумента, так что он работает с лямбдами и не требует написания шаблона класса (кредит @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 вы можете использовать шаблон лямбда (в кредит @ 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);
    });
}

Живой пример

...