Условное создание членов внутри класса - PullRequest
1 голос
/ 08 апреля 2019

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

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
};

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

Ответы [ 2 ]

4 голосов
/ 08 апреля 2019

Вы не можете использовать 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>, либо иметь одного из них в качестве члена.

<ч />

Для случая, когда вам нужен либо член, либо ничего, другой случай просто должен быть пустым типом. В 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 голос
/ 08 апреля 2019

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-интерфейс bool для Object для разделения реализации.

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

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

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

...