根据不同条件初始化类模板的成员

时间:2019-05-17 21:39:06

标签: c++ templates constructor c++17 list-initialization

我有一个包含两个构造函数的类模板,一个构造函数采用无符号类型,另一个构造函数对其自身进行常量引用,这两个构造函数在构造类时具有相同的行为。

在构造此类时,有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种情况,将以不同的方式初始化数据成员。

我不知道该如何处理。这里的所有信息都应该在编译时可用,所以我不明白为什么会有问题,但是我不知道如何设置构造函数以具有此功能。而且甚至可以做到吗?


编辑

有关类型TP的背景知识:TP均是以下任意一项:

  

类型:以字节为单位的大小:以位为单位的大小:

     
      
  • std::uint8_t 1字节8位
  •   
  • std::uint16_t 2字节16位
  •   
  • std::uint32_t 4字节32位
  •   
  • std::uint64_t 8字节64位
  •   

一旦我们根据两个大小的比较定义了3个条件,则断言的工作方式如下:传入的无符号char也是断言中条件的一部分,并且它具有一定范围的值是。这是一个表格:我将用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 个答案:

答案 0 :(得分:3)

在这种情况下,无法使用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的大小如何,也可以添加一个额外的委派层。