Использование макросов для определения большого количества удобных псевдонимов/констант: есть ли лучшая альтернатива?C++

Программы на C++. Форум разработчиков
Anonymous
 Использование макросов для определения большого количества удобных псевдонимов/констант: есть ли лучшая альтернатива?

Сообщение Anonymous »

Я пишу статическую библиотеку constexpr, в которой у меня есть тип common_v, который довольно неуклюж для использования в качестве типа в коде и предназначен для сокрытия от конечного пользователя. Исходя из этого, определяются псевдонимы, обращенные к пользователю, за которыми следуют прототипные константы. Все эти псевдонимы и константы созданы по шаблону, чтобы пользователь мог определить базовый тип с плавающей запятой:

Код: Выделить всё

template
struct general_v
{
T value;
}

template using specific_a_v = general_v;
template using specific_b_v = general_v;
template using specific_c_v = general_v;
template using specific_d_v = general_v;
template using specific_e_v = general_v;

template static constexpr specific_a_v prototype_a_v{ static_cast(1.0) };
template static constexpr specific_b_v prototype_b_v{ static_cast(1.0) };
template static constexpr specific_c_v prototype_c_v{ static_cast(1.0) };
template static constexpr specific_d_v prototype_d_v{ static_cast(1.0) };
template static constexpr specific_e_v prototype_e_v{ static_cast(1.0) };
Основная цель этой библиотеки — сделать ее использование кратким. Чтобы облегчить это, я хочу определить удобные псевдонимы и константы для каждого из ключевых типов с плавающей запятой:

Код: Выделить всё

using specific_a_f = specific_a_v;
using specific_b_f = specific_b_v;
using specific_c_f = specific_c_v;
using specific_d_f = specific_d_v;
using specific_e_f = specific_e_v;

using specific_a = specific_a_v;
using specific_b = specific_b_v;
using specific_c = specific_c_v;
using specific_d = specific_d_v;
using specific_e = specific_e_v;

using specific_a_l = specific_a_v;
using specific_b_l = specific_b_v;
using specific_c_l = specific_c_v;
using specific_d_l = specific_d_v;
using specific_e_l = specific_e_v;

static constexpr auto prototype_a_f{ prototype_a_v };
static constexpr auto prototype_b_f{ prototype_b_v };
static constexpr auto prototype_c_f{ prototype_c_v };
static constexpr auto prototype_d_f{ prototype_d_v };
static constexpr auto prototype_e_f{ prototype_e_v };

// and so on
Таким образом, вы сэкономите немного места во время использования. Однако, как вы можете видеть, это начинает быстро повторяться. Если бы это были все типы, возможно, это было бы хорошо, но тогда у меня были бы псевдонимы для типов, объединяющих вышеуказанные типы, которые, вероятно, со временем будут добавлены. Это оказывается непростой задачей при управлении кодом: каждый раз, когда я добавляю новый тип, мне приходится добавлять все удобные псевдонимы/прототипы для каждого из них.
Появляются макросы чтобы быть решением, где я могу позволить вызову макроса добавить для меня эти удобные псевдонимы/прототипы:

Код: Выделить всё

#define DEFINE_CONVENIENCE_ALIASES(name_of_type)       \
using name_of_type##_f = name_of_type##_v;      \
using name_of_type     = name_of_type##_v;     \
using name_of_type##_l = name_of_type##_v;\

#define DEFINE_CONVENIENCE_CONSTANTS(name_of_variable)                         \
static constexpr auto name_of_variable##_f = name_of_variable##_v;      \
static constexpr auto name_of_variable     = name_of_variable##_v;     \
static constexpr auto name_of_variable##_l = name_of_variable##_v;\

template using specific_a_v = general_v;
DEFINE_CONVENIENCE_ALIASES(specific_a)
template using specific_b_v = general_v;
DEFINE_CONVENIENCE_ALIASES(specific_b)
template using specific_c_v = general_v;
DEFINE_CONVENIENCE_ALIASES(specific_c)
template using specific_d_v = general_v;
DEFINE_CONVENIENCE_ALIASES(specific_d)
template using specific_e_v = general_v;
DEFINE_CONVENIENCE_ALIASES(specific_e)

template static constexpr specific_a_v prototype_a_v{ static_cast(1.0) };
DEFINE_CONVENIENCE_CONSTANTS(prototype_a)
template static constexpr specific_b_v prototype_b_v{ static_cast(1.0) };
DEFINE_CONVENIENCE_CONSTANTS(prototype_b)
template static constexpr specific_c_v prototype_c_v{ static_cast(1.0) };
DEFINE_CONVENIENCE_CONSTANTS(prototype_c)
template static constexpr specific_d_v prototype_d_v{ static_cast(1.0) };
DEFINE_CONVENIENCE_CONSTANTS(prototype_d)
template static constexpr specific_e_v prototype_e_v{ static_cast(1.0) };
DEFINE_CONVENIENCE_CONSTANTS(prototype_e)
Это выглядит намного аккуратнее. У него также есть дополнительное преимущество: новые типы с плавающей запятой могут поддерживаться путем изменения только определений макросов.
Однако я осознаю, что макросы не имеют фантастической репутации; из основных рекомендаций: «Кричите, когда видите макрос, который используется не только для контроля версий (например, #ifdef)», и я не уверен, действительно ли это использование подпадает под систему контроля версий...
Я не решаюсь использовать их без необходимости. Итак, в этой ситуации мне лучше использовать макросы? С какими неожиданными проблемами мне при этом придется столкнуться? Я бы предпочел хранить весь свой код в реальном коде C++, но я понимаю, что, поскольку это предполагает присвоение имен большому количеству удобных псевдонимов и констант, особых препятствий для этого не будет. Возможности C++, которые решат эту проблему, хотя я был бы очень рад, если бы я ошибался.

Подробнее здесь: https://stackoverflow.com/questions/790 ... is-there-a

Вернуться в «C++»