如何使用模板元编程实现这种复杂的映射?

时间:2011-09-20 21:28:24

标签: c++ performance templates struct metaprogramming

我正在尝试使用模板元编程来定义结构,但我想要做的可能需要分布在多个结构上而不是一个超级结构:

template <A, B, C>
struct ABC
{
   A a;
   B b;
   C c;
}

这是我希望实现的灵活性,因为我将使用代码生成器,并且如果可能的话,不希望具体地定义每个可能的struct-type:

  1. 可以定义A,B和C的类型。
  2. a,b或c可以是预定义和预先指定的常量(即const unsigned char a = 0x48;)或者是常规变量成员类型。
  3. 一般模式是我的代码生成器中的b将有无符号数字输入,c通常是整数(长度为1-8个字节),a将是结果的总长度。

    一些例子(不完全是需要的,只是提出一个想法):

    struct <struct1>
    {
       const unsigned char a = 'A';
       const unsigned short b = 0x1000;
       char c[10];
    }
    

    我对模板元编程知之甚少,甚至开始着手这样做,特别是对于可以预先分配或不预先分配的a和b部分。

    也许为了保持简单,我们可以假设我总是将值分配给A,B,C和a,以及b,因此a和b可以是常数并预先分配。

    最后,这些消息将被转换为char *并通过线路发送(并使用#pragma进行字节打包)

    提前感谢您的帮助!

    对于令人困惑的问题描述感到抱歉。我将尝试使用模板化结构ABC(或根据需要定义其他结构)的一些示例来澄清它。这些示例来自最终用户的观点:

    typedef ABC<100, char[10]> Msg1;
    

    将导致相当于:

    struct Msg1
    {
        const unsigned short a = sizeof(Msg1); // sizeof(Msg1) fits in unsigned short
        const unsigned char b = 100;
        char[512] c;
    }
    

    请注意,成员a和b的大小需要由模板根据Msg1的大小和传入的参数100来确定。这对我来说非常棘手。

    typedef ABC<23000, unsigned int> Msg2;
    
    struct Msg2
    {
        const unsigned char a = sizeof(Msg2);  // sizeof(Msg2) fits in unsigned char
        const unsigned short b = 23000;
        unsigned int c;
    }
    

    希望这会让它更加清晰。

3 个答案:

答案 0 :(得分:2)

好吧,要使用常量定义结构,只需使用普通模板:

template <typename A, A a_val,
          typename B, B a_val,
          typename C, C a_val>
struct ABC
{
  static const A a = a_val;
  static const B b = b_val;
  static const C c = c_val;
}

只要类型是完整的,这就可以工作。用法:

ABC<char, 'a', unsigned int, 12, std::size_t, 100> abc;

如果您需要任意数量的此类对,可以使用可变参数模板进行推广。我将常量设为静态,因为它们是类型的属性,而不是实例。使用构造函数,可以很容易地将其扩展为非整数类型。

这可能不是你想要的,所以如果我误解了请留下评论,或者更新你的问题以澄清规格。

答案 1 :(得分:1)

你想要做的事情并不是很清楚,但是从我能收集的内容来看,这里也是如此。调查boost::fusion - 可以省去一些努力。例如:

typedef unsigned char IDType
typedef unsigned short LengthType
typedef boost::array<char, 8> DataType

typedef boost::fusion::vector<IDType, LengthType, DataType> StructA;

StructA a_inst('A',0x1000, "ABCD");

这会创建一个具有给定值的StructA实例,现在如果你可以保证前两个属性总是不变的 - 你可以这样做:

typedef <unsigned char id, unsigned short len, typename DataType>
struct generic_struct
{
  DataType _data;
};

// Now a specific type looks like this
typedef generic_struct<'A', 0x1000, boost::array<char, 8> > StructA;

与后一种方法的不同之处在于StructA不需要前两个consts的存储空间,它们是 type 的一部分 - 这意味着对于序列化,你需要提供一个特定的方法,可以序列化id类型和长度(模板参数) - 但这是微不足道的。

答案 2 :(得分:0)

您似乎正在寻找的是一种指定包装2个成员的模板类并添加包含该模板的sizeof的附加成员的方法。

template <int B, class C>
struct tABC
{
    const size_t a;
    const unsigned int b;
    C c;

    tABC() : a(sizeof(*this)), b(B) {}
};

这基本上生成了您似乎正在寻找的代码。唯一缺少的是你似乎有一些规则可以选择a和b的类型。如果那些是“无论什么样的最小类型都可以容纳它们”,那么你真的需要考虑使用boost,因为它有专门设计的库。否则,我想只需打开升级代码并复制它是如何做到的。