Ограничения размера constexpr С++ 23? Итерация от 0x4000 = ок до 0x5000 = не постоянное выражение

Следующий код работает и печатает пересечение, как и ожидалось. Однако при изменении max_codepoint с 0x4000 на 0x5000 он перестает работать с ошибкой:

ConsoleApplication1.cpp(149, 30): [C2131] expression did not evaluate to a constant

Я попытался изменить 0x4000 на 0x5000 (или, точнее, на 0xffff, чтобы получить полный диапазон UTF-16) и ожидал, что это сработает. Тем не менее, это не так.

#include <array>
#include <print>
#include <vector>

using ImWchar = unsigned short;

consteval std::vector<ImWchar> ConstGetGlyphRangesLatin()
{
    return {
        0x0020, 0x00FF, // Basic Latin + Latin Supplement
    };
}

consteval std::vector<ImWchar> ConstGetGlyphRangesGW()
{
    return {
        0x20, 0x7f,
        0xa1, 0xff,
        0x100, 0x180,
        0x0391, 0x0460,
        0x2010, 0x266b,
        0x3000, 0x3020,
        0x3041, 0x3100,
        0x3105, 0x312a,
        0x3131, 0x318f,
        0xac00, 0xd7a4,
        0x4e00, 0x9fa6,
        0xf900, 0xfa6b,
        0xff01, 0xffe7
    };
}

consteval bool in_range(const ImWchar c, const std::vector<ImWchar>& range)
{
    for (size_t i = 0; i < range.size() - 1; i += 2) {
        if (c >= range[i] && c <= range[i + 1]) return true;
    }
    return false;
};

consteval std::vector<ImWchar> find_glyph_range_intersection(const std::vector<ImWchar>& range1, const std::vector<ImWchar>& range2)
{
    if (range1.empty() || range2.empty()) return {};

    std::vector<ImWchar> intersection;
    wchar_t start = 0;
    bool in_intersection = false;

    constexpr auto max_codepoint = 0x4000;
    for (ImWchar c = 0; c <= max_codepoint; ++c) {
        const bool in_both = in_range(c, range1) && in_range(c, range2);

        if (in_both && !in_intersection) {
            start = c;
            in_intersection = true;
        }
        else if (!in_both && in_intersection) {
            intersection.push_back(start);
            intersection.push_back(c - 1);
            in_intersection = false;
        }
    }

    if (in_intersection) {
        intersection.push_back(start);
        intersection.push_back(max_codepoint);
    }

    intersection.push_back(0); // Null-terminate the range
    return intersection;
}

template <typename T, size_t N>
consteval std::array<T, N> vec_to_array(const std::vector<T>& vec)
{
    std::array<T, N> arr = {};
    std::copy(vec.begin(), vec.end(), arr.begin());
    return arr;
}

consteval auto get_intersection_array()
{
    const auto latin = ConstGetGlyphRangesLatin();
    const auto gw = ConstGetGlyphRangesGW();

    const auto intersect = find_glyph_range_intersection(latin, gw);
    return vec_to_array<ImWchar, 1'000>(intersect);
}

int main()
{
    constexpr std::array arr = get_intersection_array();
    for (auto c : arr) {
        if (c != 0)
            std::print("{}, ", c);
    }
}

У меня компилируется с clang, как только я исправлю ConstGetGlyphRangesKorean. Вероятно, вы просто достигли внутреннего предела компилятора. Проверьте руководство визуальной студии, чтобы узнать, есть ли способ увеличить лимит.

Stephen Newell 11.07.2024 21:12

«Что я там не понимаю?» Это время компиляции не бесконечно. Компиляторам не обязательно позволять постоянным вычислениям продолжаться вечно. Они могут и будут останавливать выполнение, если почувствуют, что все, что вы делаете, стало патологией и не может быть завершено в разумные сроки.

Nicol Bolas 11.07.2024 21:14

Итак, вы опубликовали работающий код и в своем вопросе даете инструкции по его изменению, чтобы показать проблему, о которой вы спрашиваете? Не делай этого. Опубликуйте код, который показывает проблему.

Pete Becker 11.07.2024 21:37

@PeteBecker ничего не меняет, не так ли? Это буквально замена одной буквы.

DubbleClick 11.07.2024 22:02

@StephenNewell Интересно. Какой компилятор вы используете? Godbolt не работает на последней версии gcc x64 и последней версии msvc x64. К сожалению, я не могу найти документацию по такой настройке.

DubbleClick 11.07.2024 22:05

clang 17.0.6 с libc++ 17.0.6, x86_64 Linux (в частности, Gentoo, но я не думаю, что это имеет значение).

Stephen Newell 11.07.2024 22:19

Спасибо. Предел для gcc на самом деле немного выше, чем для MSVC, где я изначально тестировал. Найден флаг компилятора /constexpr, проблема решена.

DubbleClick 11.07.2024 22:23

@DubbleClick — речь идет о предоставлении кода, который кто-то может вырезать, вставить, скомпилировать и увидеть проблему. Когда вы просите людей оказать вам услугу, сделайте это как можно проще для них. Я бы, например, не стал беспокоиться о коде, который мне придется изменить.

Pete Becker 11.07.2024 23:21
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
8
124
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Выражение не является постоянным выражением, если для его вычисления потребуется больше шагов оценки, чем некоторый предел, определенный реализацией.

Это сделано для того, чтобы компиляторы не были вынуждены работать вечно во время компиляции. Из-за проблемы остановки в противном случае было бы невозможно решить, является ли выражение постоянным.

У компиляторов обычно есть опция, с помощью которой этот предел, определенный реализацией, можно увеличить за счет времени компиляции.

Как упоминалось в комментарии @DubbleClick под этим ответом: настройка MSVC выглядит как /constexpr:steps.

Спасибо за ответ. Если кто-то еще ищет флаг MSVC: Learn.microsoft.com/en-us/cpp/build/reference/…

DubbleClick 11.07.2024 22:24

@DubbleClick Я добавил это в ответ. Однако вы также можете предложить изменения к ответу, нажав «Изменить», или написать свой собственный ответ с более подробной информацией. Комментарии могут быть удалены, но их сохранение не гарантируется.

user17732522 11.07.2024 23:14

Альтернативой, если это возможно, является переход на менее сложный алгоритм (in_range здесь линейный, может быть логарифмический).

Jarod42 12.07.2024 15:28

Другие вопросы по теме