2009-02-04 10 views
4

Nous avons un tableau const de structures, quelque chose comme ceci:Recherché: une idée de modèle C++ pour attraper un problème, mais au moment de la compilation?

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

la structure a les suivantes:

  • size_bytes:
  • NUM_ITEMS:
  • Autres "méta-données" membres

Ainsi, la "taille totale" est size_bytes * num_items pour un élément unique. Toutes ces informations sont dans le tableau const, disponible au moment de la compilation. Mais, veuillez noter que la taille totale de _table n'est pas liée à la taille de l'EEPROM elle-même. La table _table ne reflète pas l'EEPROM, elle décrit seulement la disposition, l'utilisation et d'autres informations de type "méta-données" dont nous avons besoin. Mais, vous pouvez utiliser cette méta-donnée pour déterminer la quantité d'EEPROM que nous utilisons.

Le tableau décrit simplement les données stockées dans une EEPROM externe, qui a une taille fixe/maximale. À mesure que des entités sont ajoutées et supprimées, les entrées de la matrice const changent. Nous avons actuellement un contrôle d'exécution de la taille totale des données pour s'assurer qu'il ne dépasse pas la taille de l'EEPROM.

Toutefois, nous avons modifié plusieurs de ces vérifications d'exécution en vérifications de modèle de style static_assert, de sorte que la génération s'arrête immédiatement. Je ne suis pas un expert en template, je pourrais donc utiliser de l'aide sur celui-ci. Donc, la question: comment créer un modèle pour additionner la taille de tous les éléments (en multipliant les valeurs de chaque élément, puis en ajoutant tous les résultats), puis faire un static_assert et arrêter la construction s'ils dépassent la taille du nombre magique de l'EEPROM. Je regardais l'exemple de modèle factoriel récursif typique comme une approche, mais il ne peut pas accéder au tableau, il nécessite une valeur const (je pense).

merci beaucoup pour toute aide,

Répondre

6

Votre problème est qu'ils sont constants, mais ils ne sont pas des expressions constantes lors de l'évaluation:

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

Qu'est-ce que vous avez besoin sont vraies expressions constantes. Vous pouvez utiliser boost::mpl pour constituer un vecteur de paires mpl mpl, chacun avec une paire de constantes intégrales:

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

Maintenant, vous pouvez itérer sur les éléments de celui-ci en utilisant des algorithmes boost::mpl.Chaque int_ expose une constante statique statique value à la valeur que vous lui avez indiquée. Cela va évaluer à une expression constante:

// 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]; 

Et cela rendrait effectivement ce tableau contient 5 éléments.

Site de boost :: mpl Manuel de référence: Here

1

Si vous modifiez les valeurs comme des paramètres modèle plutôt que des arguments de constructeur ou d'une autre valeur initialisée exécution, ils sont des constantes qui peuvent être utilisées pour vos static_asserts.

Je ne suis pas sûr de savoir comment cela pourrait fonctionner pour un tableau de la structs cependant. Vous devrez peut-être déclarer vos structures en utilisant un peu de magie de préprocesseur de macro afin qu'il garde une trace de vos allocations pour vous.

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

Cela pourrait déclarer votre table et un const qui ajoute toutes les tailles, à condition qu'ils soient constants au moment de la compilation (et que vous écrivez les macros de façon appropriée, bien sûr).

0

Ceci est essentiellement la même réponse que litb, mais montre également comment ajouter les tailles jusqu'à w/o coder en dur la taille du tableau. C'est pourquoi cela semble si compliqué.

La partie pour laquelle vous avez besoin d'aide n'est pas claire. Voici comment vous utilisez les types pour suivre toutes les méta-données plutôt qu'un tableau en mémoire. Cela permet de compiler des vérifications de temps avec des énumérations que vous ne pouvez pas faire avec const int dans les structures. Si vous avez plus de métadonnées, ajoutez des paramètres supplémentaires dans le modèle pour les paramètres et stockez-les en tant que valeurs enum.

Utilisation de la bibliothèque Loki: http://loki-lib.sourceforge.net/index.php?n=Main.Development. Il est limité à 18 "Paramètres" en raison de la façon dont MakeTypeList est implémenté.

Vous pouvez utiliser TypeAt<TList, index>::Result::size_bytes (par exemple) pour accéder aux métadonnées.

#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; 
    } 
0

De mon fauteuil, je serais enclin à essayer d'exprimer les données de configuration en tant que structure de sorte que la taille peut être vérifiée au moment de la compilation (tout assert statique peut le faire). Difficile de dire si ce serait une approche appropriée, basée sur les informations fournies, mais également, pour les mêmes raisons, je ne vois pas de raison immédiate de le rejeter.

Une traduction de base de la table serait quelque chose comme:

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

(Insérer la magie du compilateur approprié pour éliminer le rembourrage et l'alignement, mais dans la pratique char semble généralement à l'abri de ce genre de chose sur la plupart des plate-forme/compilateur combinaisons.)

Ensuite, pour obtenir les tailles on peut utiliser sizeof selon le cas. Si la table de valeurs réelle est toujours nécessaire, elle peut être générée de cette manière. Ce serait un peu moche, mais facilement - assez caché derrière une macro.

Si cela serait «mieux» qu'une approche plus lourde, cela dépend probablement du marché cible.

+0

Oui, nous avons utilisé l'approche sizeof sur d'autres tables. Mais, je suppose que je n'étais pas 100% clair. Cette table ressemble plus à une table "méta-données". Il décrit l'EEPROM, sa structure et la manière dont chaque élément doit être utilisé. Ce n'est pas une réplique "sizeof" exacte de l'EEPROM. merci –

Questions connexes