Почему, если constexpr не может обойти оценку constexpr? - PullRequest
0 голосов
/ 30 декабря 2018

Я строю статический цикл для диспетчеризации типов с использованием макросов.Вот то, чего я достиг до сих пор.

#define LOOP(n, f)                                            \
    static_assert(n <= 8 && "static loop size should <= 8");  \
    do {                                                      \
        if constexpr (n >= 8)                                 \
            f(std::integral_constant<size_t, n - 8>());       \
        if constexpr (n >= 7)                                 \
            f(std::integral_constant<size_t, n - 7>());       \
        if constexpr (n >= 6)                                 \
            f(std::integral_constant<size_t, n - 6>());       \
        if constexpr (n >= 5)                                 \
            f(std::integral_constant<size_t, n - 5>());       \
        if constexpr (n >= 4)                                 \
            f(std::integral_constant<size_t, n - 4>());       \
        if constexpr (n >= 3)                                 \
            f(std::integral_constant<size_t, n - 3>());       \
        if constexpr (n >= 2)                                 \
            f(std::integral_constant<size_t, n - 2>());       \
        if constexpr (n >= 1)                                 \
            f(std::integral_constant<size_t, n - 1>());       \
    } while (0);

template <typename T> constexpr size_t tupleSize(T&) { return tuple_size_v<T>; }

int main() {
    auto t = std::make_tuple(1, "string", 0.2, 3, 1, 1, 1);
    LOOP(tupleSize(t), [&](auto i) { cout << std::get<i>(t) << endl; });
    return 0;
}

И ссылка Godbolt https://godbolt.org/z/GcMZI3

Вопрос в том, почему первые четыре ветки терпят неудачу при компиляции?

1 Ответ

0 голосов
/ 30 декабря 2018

Не используйте макрос, вместо этого используйте шаблон функции.if constexpr работает , отбрасывая не занятую ветвь в зависимости от текущего создания шаблона.

template <std::size_t n, typename F>
void loop(F&& f)
{
    static_assert(n <= 8 && "static loop size should <= 8");
    if constexpr (n >= 8)
        f(std::integral_constant<size_t, n - 8>());
    if constexpr (n >= 7)
        f(std::integral_constant<size_t, n - 7>());
    if constexpr (n >= 6)
        f(std::integral_constant<size_t, n - 6>());
    if constexpr (n >= 5)
        f(std::integral_constant<size_t, n - 5>());
    if constexpr (n >= 4)
        f(std::integral_constant<size_t, n - 4>());
    if constexpr (n >= 3)
        f(std::integral_constant<size_t, n - 3>());
    if constexpr (n >= 2)
        f(std::integral_constant<size_t, n - 2>());
    if constexpr (n >= 1)
        f(std::integral_constant<size_t, n - 1>());
}

Использование:

int main() {
    constexpr auto t = std::make_tuple(1, "string", 0.2, 3);
    loop<tupleSize(t)>([&](auto i) { cout << std::get<i>(t) << endl; });
    return 0;
}

живой пример на godbolt.org


От cppreference :

Если constexprесли выражение появляется внутри шаблонной сущности, и если условие не зависит от значения после создания экземпляра, то исключенный оператор не создается при создании экземпляра вмещающего шаблона.

За пределами шаблона отбрасываемый оператор полностью проверяется.если constexpr не заменяет директиву предварительной обработки #if

...