Построение массива const из constexpr
Предположим, у меня есть следующий закрытый constexpr в классе:
static constexpr uint16_t square_it(uint16_t x)
{
return std::pow(x, 2);
}
Затем я хочу построить массив статических констант из этих значений для целых чисел до 255 в том же разделе того же класса, используя вышеуказанный constexpr:
static const uint16_t array_of_squares[256] =
{
//something
};
Я бы хотел, чтобы массив создавался во время компиляции, а не во время выполнения, если это возможно. Я думаю, что первая проблема заключается в том, что использование выражений типа std::pow в constexpr недопустимо в соответствии с ISO C++ (хотя возможно и разрешено arm-gcc?), Так как оно может возвращать ошибку домена. Фактическое выражение, которое я хочу использовать, является довольно сложной функцией, включающей std::exp.
Обратите внимание, что у меня не так много доступной библиотеки std, так как я собираю небольшой микропроцессор Cortex M4.
Есть ли более подходящий способ сделать это, скажем, с помощью макросов препроцессора? Я бы очень хотел избежать использования чего-то вроде внешнего скрипта Python для вычисления таблицы каждый раз, когда она должна быть изменена во время разработки, а затем вставлять ее.
2 ответа
Как насчет этого?
constexpr uint16_t square_it(uint16_t v) { return v*v; }
template <size_t N, class = std::make_index_sequence<N>>
struct gen_table;
template <size_t N, size_t... Is>
struct gen_table<N, std::index_sequence<Is...>> {
static const uint16_t values[N] = {square_it(Is)...};
};
constexpr auto&& array_of_squares = gen_table<256>::values;
Я понятия не имею, поддерживает ли этот микропроцессор такую операцию. Может не иметь make_index_sequence
в вашей стандартной библиотеке (хотя вы можете найти реализации на SO), и, возможно, этот экземпляр шаблона займет слишком много памяти. Но, по крайней мере, это где-то работает.
Проблема, как вы говорите, заключается в том, что стандартные функции библиотеки C обычно не помечены constexpr
,
Лучший обходной путь здесь, если вам нужно использовать std::exp
, это написать свою собственную реализацию, которая может быть запущена во время компиляции. Если это должно быть сделано во время компиляции, то оптимизация, вероятно, не нужна, она должна быть точной и умеренно эффективной.
Кто-то задал вопрос о том, как это сделать здесь давным-давно. Вы можете использовать идею оттуда и переписать как constexpr
функция в C++11, хотя вам придется реорганизовать ее, чтобы избежать цикла for. В C++14 потребуется меньше рефакторинга.
Вы также можете попробовать сделать это строго через шаблоны, но это будет более болезненным, и double
не может быть параметром шаблона, поэтому будет сложнее.