#c #class #c 17 #if-constexpr
#c #класс #c 17 #if-constexpr
Вопрос:
Возможно ли сделать что-то вроде:
template <unsigned majorVer, unsigned minorVer>
class Object
{
public:
if constexpr ((majorVer == 1) amp;amp; (minorVer > 10))
bool newField;
else
int newInt
};
или
template <unsigned majorVer, unsigned minorVer>
class Object
{
public:
if constexpr ((majorVer == 1) amp;amp; (minorVer > 10))
bool newField;
// Nothing other wise
};
используете c 17?
Я хотел бы изменить структуру класса на основе некоторого условия, которое можно проверить во время компиляции. Есть ли какой-либо способ добиться этого?
Комментарии:
1. Специализация на шаблонах.
2. Это возможно в языке D с
static if
конструкцией, но в C вам нужно играть в игры с наследованием отstd::condtitional_t<your condition, struct with member, empty struct>
и полагаться на оптимизацию пустой базы. Хороший доклад Андрея Александреску об этом: youtube.com/watch ? v=tcyb1lpEHm0
Ответ №1:
Вы не можете использовать if constexpr
для этого. Вам пришлось бы свернуть их в один элемент, используя что-то вроде std::conditional
:
std::conditional_t<(majorVer == 1) amp;amp; (minorVer > 10), bool, int> newField;
В качестве альтернативы, вы можете обернуть каждый из двух типов полей в их собственный тип:
struct A { bool newField; };
struct B { int newInt; };
И либо наследовать от std::conditional_t<???, A, B>
, либо иметь один из них в качестве члена.
В случае, когда вам нужен либо элемент, либо ничего, другой случай просто должен быть пустым типом. В C 20 это:
struct E { };
[[no_unique_address]] std::conditional_t<some_condition(), bool, E> newField;
В C 17 и более ранних версиях вы захотите наследовать от этого, чтобы гарантировать запуск оптимизации пустой базы:
struct B { bool field; };
struct E { };
template <unsigned majorVer, unsigned minorVer>
class Object : private std::conditional_t<some_condition(), B, E>
{ ... };
Комментарии:
1. Спасибо Барри за ответ. Что, если я хочу создать элемент только тогда, когда выполнено условие (в противном случае никакого элемента не должно быть)? Это тоже можно сделать с помощью conditional_t?
2. @Arun Конечно, пусть альтернативой будет какой-нибудь пустой тип.
3. @Barry это создаст элемент с пустым типом, что не то же самое, что вообще никакого элемента.
4. @Barry В идеале, как уже упоминал n.m, я бы хотел, чтобы элементы вообще не создавались. Возможно ли сделать что-то подобное?
5. @arun наследуется от пустой структуры.
Ответ №2:
if-constexpr относится к потоку управления, а не к расположению памяти. Возможно, для этого хорошо подойдет отражение TS. Однако, пока это не доступно, вам понадобятся другие методы.
constexpr bool useLegacyInt(unsigned major, unsigned minor)
{
return (majorVer <= 1) amp;amp; (minorVer <= 10));
}
template<bool>
class ObjectBase
{
book newField;
};
template<>
class ObjectBase<true>
{
int newInt;
};
template <unsigned majorVer, unsigned minorVer>
class Object : public ObjectBase<useLegacyInt (majorVer, minorVer)>
{};
Основываясь на этом, вы могли бы внести некоторые уточнения. Вы влияете не только на члены, но и на методы. Таким образом, установщики и получатели … могут иметь разную подпись. Защищенные вспомогательные функции могли бы предоставлять bool API для Object для разделения реализации.
Наконец, я бы не рекомендовал использовать bool, я скорее ожидаю перечисления, поскольку это может иметь несколько значений.
Наследование от более ранней версии также может быть возможным, если новая версия только расширяется. А с некоторыми аргументами шаблона по умолчанию вы можете даже делать более причудливые вещи.
Имейте в виду, что такого рода обратная совместимость может очень быстро усложниться. Иногда лучше просто скопировать полный код в устаревшую версию и сохранить его как есть, без вмешательства нового API. Это за счет дублированного кода.