4

我们有一个 const 结构数组,如下所示:

static const SettingsSuT _table[] = { {5,1}, {1,2}, {1,1} 等 };

该结构具有以下内容:

  • 大小字节:
  • 数量:
  • 其他“元数据”成员

所以“总大小”是单个元素的 size_bytes*num_items 。所有这些信息都在 const 数组中,在编译时可用。但是,请注意,_table 的总大小与 EEPROM 本身的大小无关。_table 不镜像 EEPROM,它只描述了布局、使用和其他我们需要的“元数据”类型信息。但是,您可以使用此元数据来确定我们正在使用的 EEPROM 数量。

该数组仅描述了存储在具有固定/最大大小的外部 EEPROM 中的数据。随着功能的添加和删除, const 数组中的条目会发生变化。我们目前对数据的总大小进行运行时检查,以确保它不超过 EEPROM 大小。

但是,我们已经将其中许多运行时检查更改为 static_assert 样式的模板检查,以便立即停止构建。我不是模板专家,所以可以在这方面使用一些帮助。

所以,问题是:如何创建一个模板来将所有元素的大小相加(将每个元素的值相乘,然后将所有结果相加),然后执行 static_assert 并在它们超过幻数大小时停止构建的 EEPROM。我将典型的递归阶乘模板示例作为一种方法,但它无法访问数组,它需要一个 const 值(我认为)。

非常感谢您的帮助,

4

4 回答 4

6

您的问题是它们是常量,但在评估时它们不是常量表达式:

// f is constant, but its value not known at compile-time
int const f = rand() % 4;

您需要的是真正的常量表达式。您可以使用boost::mplmpl 对组成一个 mpl 向量,每个 mpl 对都有一对整数常数:

using namespace boost::mpl;
typedef vector<
    pair< int_<5>, int_<1> >,
    pair< int_<1>, int_<2> >,
    pair< int_<1>, int_<1> >,
    > numbers;

boost::mpl现在,您可以使用算法迭代它的项目。每个int_都公开一个静态 int 常量value,设置为您告诉它的值。这将评估为一个常量表达式:

// get at the first element of the pair, located in the first element
// of the vector. Then get its ::value member. 
int array[at<numbers, 0>::type::first::value];

这实际上会使该数组包含 5 个元素。

boost::mpl 参考手册的网站:这里

于 2009-02-04T22:35:43.930 回答
1

如果您将值更改为模板参数而不是构造函数参数或其他一些运行时初始化值,那么它们是可用于您的 static_asserts 的常量。

我不确定这如何适用于结构数组。您可能需要使用一些宏预处理器魔术来声明您的结构,以便它跟踪您的分配。

BEGIN_EEPROM_STRUCT_TABLE()
  STRUCT(size, num_bytes)
  // etc.
END_EEPROM_STRUCT_TABLE()

这可能会声明您的表和一个将所有大小相加的 const,前提是它们在编译时是恒定的(当然,您要适当地编写宏)。

于 2009-02-04T19:33:37.620 回答
0

这基本上与 litb 的答案相同,但也显示了如何在不对数组大小进行硬编码的情况下将大小相加。这就是为什么它看起来如此复杂。

目前尚不清楚您需要帮助的部分。下面是如何使用类型来跟踪所有元数据而不是内存中的数组。这允许使用枚举进行编译时检查,而您不能在结构中使用 const int 进行检查。如果您有更多元数据,请在设置模板中添加其他参数并将它们存储为枚举值。

使用 Loki 库: http://loki-lib.sourceforge.net/index.php?n= Main.Development。由于 MakeTypeList 的实现方式,它被限制为 18 个“设置”。

您可以使用TypeAt<TList, index>::Result::size_bytes(例如)访问元数据。

   #include "loki-0.1.7\include\loki\typelist.h"
   #include "loki-0.1.7\include\loki\static_check.h"

   using namespace Loki;
   using namespace Loki::TL;

   // based on the Length<> template from loki for adding up the sizes
   template <class TList> struct TotalSize;
   template <> struct TotalSize<NullType>
   { enum { value = 0 }; };
   template <class T, class U>
   struct TotalSize< Typelist<T, U> >
   { enum { value = T::size_bytes*T::num_items + TotalSize<U>::value }; };

   // struct for holding the sizes (and other meta data 
   // if you add extra template args and enum values)
   template <size_t s, size_t n> struct Settings
   { enum { size_bytes = s, num_items = n }; };

   // the table of setting structs (limited to 18)
   typedef MakeTypelist< Settings<5,1>, Settings<1,2>, Settings<1,1> >
   SettingsSuT;

   int _tmain(int argc, _TCHAR* argv[])
   {
       LOKI_STATIC_CHECK(TotalSize< SettingsSuT::Result >::value == 8,is8);
       // this will trigger at compile time if uncommented
       //LOKI_STATIC_CHECK(TotalSize< SettingsSuT::Result >::value != 8,isnt8);

       int x = TotalSize< SettingsSuT::Result >::value;
       return 0;
   }
于 2009-02-05T22:56:14.277 回答
0

在我的扶手椅上,我倾向于尝试将配置数据表示为一个结构,以便可以在编译时检查大小(任何静态断言都可以做到这一点)。根据所提供的信息,很难说这是否是一种合适的方法,但同样,基于同样的理由,我看不出有任何直接的理由来驳回它。

表格的基本翻译如下:

struct SettingsTable
{
    char a[5][1];//maybe call it "featureX_conf", or whatever...
    char b[1][2];
    char c[1][1];
};

(插入合适的编译器魔法来移除填充和对齐,尽管在实践中char似乎通常对大多数平台/编译器组合上的这种事情免疫。)

然后获得可以sizeof酌情使用的尺寸。如果仍然需要实际的值表,则可以通过这种方式生成。它会有点难看,但很容易隐藏在宏后面。

这是否比模板重的方法“更好”可能取决于目标市场。

于 2009-02-06T00:19:22.143 回答