Инициализация члена шаблона класса на основе различных условий

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

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

Класс выглядит примерно так:

template<typename T>
struct Foo {
    T data;

    template<typename P>
    Foo( const P val, const unsigned char c ) :
    data { static_cast<T>( val /* some operation done to val based on each case*/ ) } {
        assert( /* based on cases above,
                and each case has its own conditions to assert */ ); 
    }

    template<typename P>
    Foo( const Foo<P>& f, const unsigned char c ) :
    data{ static_cast<T>( Foo.val /* some operation done to val based on each case*/ ) } {
        assert( /* based on cases above, 
                and each case has its own conditions to assert */ );
};

3 случая заключаются в следующем:

case 1: if( sizeof(P) > sizeof(T) )
           construct Foo<T> with these conditions,
           initialize member data in this specific way
           and assert accordingly
case 2: if( sizeof(T) > sizeof(P) )
           construct Foo<T> with these conditions,
           initialize member data in this specific way
           and assert accordingly
case 3: if ( sizeof(T) == sizeof(P) )
           construct Foo<T> with these conditions,
           initialize member data in this specific way
           and assert accordingly

Есть ли простой способ сделать это? Помните, что элемент инициализируется через список инициализаторов конструкторов, но элемент данных будет инициализироваться по-разному, все в зависимости от 3 приведенных выше случаев.

Я не знаю, как я мог бы подойти к этому. Вся информация здесь должна быть доступна во время компиляции, поэтому я не понимаю, почему должны быть проблемы, но я не знаю, как настроить конструкторы, чтобы иметь эту функциональность. Кроме того, это может быть даже сделано?


РЕДАКТИРОВАТЬ

Немного предыстории о типах T & P : оба T & P являются следующими:

Типы: Размер в байтах: Размер в битах:

  • std::uint8_t 1 байт 8 бит
  • std::uint16_t 2 байта 16 бит
  • std::uint32_t 4 байта 32 бита
  • std::uint64_t 8 байт, 64 бита

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

using u8  = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;

if ( sizeof(P) > sizeof(T) )
   // comparision formula:
   // idx <= (((sizeof(P) / sizeof(T)) - 1)
   // Foo<T = u8> From: Foo<P = u16> idx[0,1], Foo<P =u32> idx[0,3], Foo<P = u64> idx[0,7]
   // Foo<T = u16> From: Foo<P = u32> idx[0,1], Foo<P = u64> idx[0,3]
   // Foo<T = u32> From: Foo<P = u64> idx[0,1]

if ( sizeof(T) > sizeof(P) )
   // comparision formula:
   // idx <= (((sizeof(T) / sizeof(P)) - 1)
   // Foo<T = u16> From: Foo<P = u8> idx[0,1]
   // Foo<T = u32> From: Foo<P = u8> idx[0,4], Foo<P = u16> idx[0,1]
   // Foo<T = u64> From: Foo<P = u8> idx[0,7], Foo<P = u16> idx[0,3], Foo<P = u32> idx[0,1]

if ( sizeof(P) == sizeof(T) ) {
   // no conditional checks
   // no assertion
   // in this case idx is not used and is not a part of any calculation
   // the two sizes match so it's just a normal initialization.

Всего 1 ответ


Это ситуация, if constexpr не может быть использован, и вам придется прибегнуть к SFINAE. Сначала делегируйте конструкцию из конструктора Foo<P> конструктору P :

template<typename P>
Foo(const Foo<P>& f, const unsigned char c) : Foo(f.val, c) {}

Конструктор P просто должен иметь три варианта, точно один из которых включен в зависимости от размера P :

template<typename P, std::enable_if_t<(sizeof(P) > sizeof(T))>* = nullptr>
Foo(P val, const unsigned char c) : data(...) {}

template<typename P, std::enable_if_t<sizeof(P) == sizeof(T)>* = nullptr>
Foo(P val, const unsigned char c) : data(...) {}

template<typename P, std::enable_if_t<(sizeof(P) < sizeof(T))>* = nullptr>
Foo(P val, const unsigned char c) : data(...) {}

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


Есть идеи?

10000