Следующий код работает и печатает пересечение, как и ожидалось. Однако при изменении 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);
}
}
«Что я там не понимаю?» Это время компиляции не бесконечно. Компиляторам не обязательно позволять постоянным вычислениям продолжаться вечно. Они могут и будут останавливать выполнение, если почувствуют, что все, что вы делаете, стало патологией и не может быть завершено в разумные сроки.
Итак, вы опубликовали работающий код и в своем вопросе даете инструкции по его изменению, чтобы показать проблему, о которой вы спрашиваете? Не делай этого. Опубликуйте код, который показывает проблему.
@PeteBecker ничего не меняет, не так ли? Это буквально замена одной буквы.
@StephenNewell Интересно. Какой компилятор вы используете? Godbolt не работает на последней версии gcc x64 и последней версии msvc x64. К сожалению, я не могу найти документацию по такой настройке.
clang 17.0.6 с libc++ 17.0.6, x86_64 Linux (в частности, Gentoo, но я не думаю, что это имеет значение).
Спасибо. Предел для gcc на самом деле немного выше, чем для MSVC, где я изначально тестировал. Найден флаг компилятора /constexpr, проблема решена.
@DubbleClick — речь идет о предоставлении кода, который кто-то может вырезать, вставить, скомпилировать и увидеть проблему. Когда вы просите людей оказать вам услугу, сделайте это как можно проще для них. Я бы, например, не стал беспокоиться о коде, который мне придется изменить.
Выражение не является постоянным выражением, если для его вычисления потребуется больше шагов оценки, чем некоторый предел, определенный реализацией.
Это сделано для того, чтобы компиляторы не были вынуждены работать вечно во время компиляции. Из-за проблемы остановки в противном случае было бы невозможно решить, является ли выражение постоянным.
У компиляторов обычно есть опция, с помощью которой этот предел, определенный реализацией, можно увеличить за счет времени компиляции.
Как упоминалось в комментарии @DubbleClick под этим ответом: настройка MSVC выглядит как /constexpr:steps.
Спасибо за ответ. Если кто-то еще ищет флаг MSVC: Learn.microsoft.com/en-us/cpp/build/reference/…
@DubbleClick Я добавил это в ответ. Однако вы также можете предложить изменения к ответу, нажав «Изменить», или написать свой собственный ответ с более подробной информацией. Комментарии могут быть удалены, но их сохранение не гарантируется.
Альтернативой, если это возможно, является переход на менее сложный алгоритм (in_range
здесь линейный, может быть логарифмический).
У меня компилируется с clang, как только я исправлю
ConstGetGlyphRangesKorean
. Вероятно, вы просто достигли внутреннего предела компилятора. Проверьте руководство визуальной студии, чтобы узнать, есть ли способ увеличить лимит.