Требуется: идея шаблона C ++ для решения проблемы, но во время компиляции? - PullRequest
4 голосов
/ 04 февраля 2009

У нас есть константный массив структур, примерно такой:

static const SettingsSuT _table [] = {{5,1}, {1,2}, {1,1} и т. Д.};

структура имеет следующее:

  • size_bytes:
  • число_объекты:
  • Другие члены "метаданных"

Таким образом, «общий размер» равен size_bytes * num_items для одного элемента. Вся эта информация находится в массиве const, доступном во время компиляции. Но, обратите внимание, общий размер _table не связан с размером самой EEPROM. _table не отражает EEPROM, он только описывает структуру, использование и другую информацию типа метаданных, которая нам нужна. Но вы можете использовать эти метаданные для определения количества используемой нами ЭСППЗУ.

Массив просто описывает данные, которые хранятся во внешней EEPROM, которая имеет фиксированный / максимальный размер. По мере добавления и удаления функций записи в массиве const изменяются. В настоящее время мы выполняем проверку общего размера данных во время выполнения, чтобы убедиться, что они не превышают размер EEPROM.

Однако во многих из этих проверок во время выполнения мы перешли к проверкам шаблонов в стиле static_assert, поэтому сборка немедленно останавливается. Я не эксперт по шаблонам, поэтому мог бы помочь с этим.

Итак, вопрос: как создать шаблон, чтобы сложить размер всех элементов (умножить значения каждого элемента, а затем сложить все результаты), а затем выполнить static_assert и остановить сборку, если они превышают магическое число размер EEPROM. Я рассматривал типичный пример рекурсивного факториального шаблона как один из подходов, но он не может получить доступ к массиву, он требует значения const (я думаю).

большое спасибо за любую помощь,

Ответы [ 4 ]

6 голосов
/ 05 февраля 2009

Ваша проблема в том, что они являются постоянными, но они не являются константными выражениями при оценке:

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

Что вам нужно, так это истинные константные выражения. Вы можете использовать boost::mpl для создания вектора 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 Справочное руководство: Здесь

1 голос
/ 04 февраля 2009

Если вы измените значения в качестве параметров шаблона, а не аргументов конструктора или какого-либо другого инициализированного значения во время выполнения, то они являются константами, которые можно использовать для ваших static_asserts.

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

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

Возможно, это может объявить вашу таблицу и const, который суммирует все размеры, при условии, что они постоянны во время компиляции (и что вы, конечно, правильно пишете макросы).

0 голосов
/ 06 февраля 2009

С моего кресла я был бы склонен попытаться выразить данные конфигурации в виде структуры, чтобы можно было проверить размер во время компиляции (любой статический оператор может сделать это). Трудно сказать, будет ли это подходящим подходом, основанным на предоставленной информации, но в равной степени на тех же основаниях я не вижу непосредственной причины отклонить его.

Базовый перевод таблицы будет выглядеть примерно так:

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

(Вставьте подходящую магию компилятора для удаления отступов и выравнивания, хотя на практике char, как правило, кажется невосприимчивым к такого рода вещам в большинстве комбинаций платформа / компилятор.)

Затем, чтобы получить размеры, можно использовать sizeof в зависимости от ситуации. Если фактическая таблица значений все еще необходима, она может быть сгенерирована таким образом. Было бы немного некрасиво, но достаточно легко спрятаться за макросом.

Будет ли это "лучше", чем более сложный подход, вероятно, зависит от целевого рынка.

0 голосов
/ 06 февраля 2009

По сути, это тот же ответ, что и litb, но также показано, как добавить размеры без жесткого кодирования размера массива. Вот почему это кажется таким сложным.

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

Использование библиотеки Loki: http://loki -lib.sourceforge.net / index.php? N = Main.Development . Он ограничен 18 «настройками» из-за того, как реализован MakeTypeList.

Вы можете использовать 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;
   }
...