Условное создание членов внутри класса

Можно ли сделать что-то вроде:

template <unsigned majorVer, unsigned minorVer>
class Object
{
public:

    if constexpr ((majorVer == 1) && (minorVer > 10))
        bool newField;
    else
        int newInt
};

или

template <unsigned majorVer, unsigned minorVer>
class Object
{
public:

    if constexpr ((majorVer == 1) && (minorVer > 10))
        bool newField;
    // Nothing other wise
};

используя С++ 17? Я хотел бы изменить структуру класса на основе некоторого условия, которое можно проверить во время компиляции. Есть ли способ добиться этого?

Специализация шаблона.

n. 1.8e9-where's-my-share m. 08.04.2019 05:35

Это возможно в языке D с конструкцией static if, но в C++ вам нужно играть в игры с наследованием от std::condtitional_t<your condition, struct with member, empty struct> и полагаться на пустую базовую оптимизацию. Хороший разговор об этом от Андрея Александреску: youtube.com/watch?v=tcyb1lpEHm0

Dmitry Gordon 08.04.2019 11:41
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
2
498
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Вы не можете использовать if constexpr для этого. Вам нужно будет свернуть их в один член, используя что-то вроде std::conditional:

std::conditional_t<(majorVer == 1) && (minorVer > 10), bool, int> newField;

В качестве альтернативы вы можете обернуть каждый из двух типов полей в свой собственный тип:

struct A { bool newField; };
struct B { int newInt; };

И либо наследовать от std::conditional_t<???, A, B>, либо иметь одного из них в качестве члена.


В случае, когда вам нужен либо элемент, либо ничего, в другом случае просто должен быть пустой тип. В С++ 20 это:

struct E { };
[[no_unique_address]] std::conditional_t<some_condition(), bool, E> newField;

В С++ 17 и более ранних версиях вы захотите наследовать это, чтобы убедиться, что пустая базовая оптимизация срабатывает:

struct B { bool field; };
struct E { };

template <unsigned majorVer, unsigned minorVer>
class Object : private std::conditional_t<some_condition(), B, E>
{ ... };

Спасибо Барри за ответ. Что делать, если я хочу создать член только тогда, когда условие выполнено (в противном случае член не должен быть там)? Можно ли это сделать с помощью conditional_t?

Arun 08.04.2019 05:26

@Arun Конечно, альтернативой может быть какой-то пустой тип.

Barry 08.04.2019 05:32

@Barry это создаст член с пустым типом, что не равнозначно отсутствию члена.

n. 1.8e9-where's-my-share m. 08.04.2019 05:36

@Barry В идеале, как уже упоминал nm, я бы хотел, чтобы вообще не создавались участники. Можно ли сделать что-то подобное?

Arun 08.04.2019 05:37

@arun наследуется от пустой структуры.

Yakk - Adam Nevraumont 08.04.2019 07:22

@н.м. Помидор, помидор? Это в основном то же самое.

Barry 08.04.2019 14:20

if-constexpr относится к потоку управления, а не к структуре памяти. Возможно, отражение TS могло бы хорошо подойти для этого. Однако, пока это не доступно, вам понадобятся другие методы.

 constexpr bool useLegacyInt(unsigned major, unsigned minor)
 {
      return (majorVer <= 1) && (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)>
   {};

Исходя из этого, можно сделать некоторые уточнения. Вы влияете не только на участников, но и на методы. Так что сеттеры и геттеры... могут иметь другую подпись. Защищенные вспомогательные функции могут предоставлять логический API для Object для разделения реализации.

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

Наследование от более ранней версии также возможно, если новая версия только расширяется. А с некоторыми аргументами шаблона по умолчанию вы можете делать еще больше причудливых вещей.

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

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