71 votes

Création programmée de tableaux statiques au moment de la compilation en C++.

On peut définir un tableau statique au moment de la compilation comme suit :

const std::size_t size = 5;    
unsigned int list[size] = { 1, 2, 3, 4, 5 };

Question 1 - Est-il possible, en utilisant divers types de techniques de métaprogrammation, d'attribuer ces valeurs de manière "programmatique" au moment de la compilation ?

Question 2 - En supposant que toutes les valeurs du tableau soient les mêmes, à l'exception de quelques-unes, est-il possible d'attribuer des valeurs de manière sélective au moment de la compilation, de manière programmatique ?

eg :

const std::size_t size = 7;        
unsigned int list[size] = { 0, 0, 2, 3, 0, 0, 0 };
  1. Les solutions utilisant C++0x sont les bienvenues
  2. Le tableau peut être assez grand, quelques centaines d'éléments
  3. Pour l'instant, le tableau ne comprendra que les types de POD
  4. On peut également supposer que la taille du le tableau sera connue à l'avance, de façon statique et conforme au temps de compilation de manière statique.
  5. Les solutions doivent être en C++ (pas de script, pas de macros, pas de pp ou de solutions basées sur un générateur de code, s'il vous plaît)

UPDATE : La solution de Georg Fritzsche est étonnante, elle nécessite un peu de travail pour la faire compiler sur les compilateurs msvc et intel, mais elle constitue néanmoins une approche très intéressante du problème.

5 votes

@GMan : L'image est telle que je l'ai expliquée, je veux savoir s'il est possible de remplir un tableau statique au moment de la compilation en utilisant seulement c++. pas d'intentions cachées, etc.

3 votes

Le commentaire de @Hippicoder @GMan est pertinent, car vous ne pouvez pas le faire en C++ ni en C++0x. Fournissez aux lecteurs le contexte, et les gourous vous trouveraient une solution (alternative)adaptée au problème initial.

0 votes

@Hippicoder : Eh bien, par exemple, d'où viennent les valeurs de votre exemple ? Quelle est leur relation avec l'environnement de compilation ? Viennent-elles d'un fichier texte ? Sont-elles des drapeaux indiquant si les macros sont définies ? Sont-elles des compteurs de quelque sorte ?

87voto

Georg Fritzsche Points 59185

Ce qui s'en rapproche le plus, c'est l'utilisation des fonctionnalités de C++0x pour initialiser les tableaux locaux ou les tableaux de membres de modèles à partir d'une liste d'arguments de modèles variadiques.
Cela est bien sûr limité par la profondeur maximale d'instanciation des modèles et il faudrait mesurer si cela fait une différence notable dans votre cas.

Ejemplo:

template<unsigned... args> struct ArrayHolder {
    static const unsigned data[sizeof...(args)];
};

template<unsigned... args> 
const unsigned ArrayHolder<args...>::data[sizeof...(args)] = { args... };

template<size_t N, template<size_t> class F, unsigned... args> 
struct generate_array_impl {
    typedef typename generate_array_impl<N-1, F, F<N>::value, args...>::result result;
};

template<template<size_t> class F, unsigned... args> 
struct generate_array_impl<0, F, args...> {
    typedef ArrayHolder<F<0>::value, args...> result;
};

template<size_t N, template<size_t> class F> 
struct generate_array {
    typedef typename generate_array_impl<N-1, F>::result result;
};

Utilisation pour votre 1..5 cas :

template<size_t index> struct MetaFunc { 
    enum { value = index + 1 }; 
};

void test() {
    const size_t count = 5;
    typedef generate_array<count, MetaFunc>::result A;

    for (size_t i=0; i<count; ++i) 
        std::cout << A::data[i] << "\n";
}

2 votes

Une note concernant la profondeur d'instanciation des modèles, msvc meurt à environ 1000, gcc a une option pour définir la profondeur récursive, j'ai été en mesure de créer un lut de 512 éléments avec cette suggestion - les temps de compilation sont évidemment un peu plus longs que d'avoir le lut codé en dur dans le source, mais dans l'ensemble cela fonctionne bien !!! :D

1 votes

Incroyable ! Il permet essentiellement la concaténation / extension de tableaux que je ne pouvais pas réaliser en C++03 avec metatemplate. Je pense que vous devriez paramétrer ArrayHolder avec la MetaFunction cependant, afin de pouvoir définir plus d'un tableau avec une arité donnée.

0 votes

@Matthieu : Si les valeurs sont différentes, il s'agit d'un type différent, si elles sont identiques, je ne veux pas d'un type en double ici - est-ce que je rate quelque chose ?

6voto

Matthieu M. Points 101624

Eh bien, vos exigences sont si vagues qu'il est difficile d'y faire quoi que ce soit... La question principale est bien sûr : d'où viennent ces valeurs ?

De toute façon, une construction en C++ peut être envisagée en 4 étapes :

  • Étapes de pré-construction : script génération d'en-tête/source à partir d'autres formats.
  • Prétraitement
  • Instanciations de modèles
  • Compilation proprement dite

Si vous souhaitez exclure la génération script, il vous reste alors 2 alternatives : Le prétraitement et la programmation de méta-modèles.

À ma connaissance, il n'y a aucun moyen pour la programmation de méta-modèles de faire l'affaire ici, car pour autant que je sache, il n'est pas possible de concaténer deux tableaux au moment de la compilation. Il nous reste donc le sauveur du jour : Programmation des préprocesseurs

Je suggère de faire appel à une bibliothèque à part entière pour nous aider : Préprocesseur Boost .

D'un intérêt particulier ici :

Si seulement nous savions où prendre les valeurs, nous pourrions donner des exemples plus significatifs.

3 votes

Consultez la réponse de Georg Fritzsche : en utilisant les modèles variadiques C++0x et l'initialisation des tableaux statiques à partir de listes varadiques, il a réussi à trouver une solution méta-modèle !

4voto

Michael Anderson Points 21181

Que diriez-vous de construire une structure imbriquée en utilisant des modèles, et de la couler comme un tableau du bon type. L'exemple ci-dessous fonctionne pour moi, mais j'ai le sentiment que je suis soit en train de marcher dans un comportement non défini, soit très proche de celui-ci.

#include <iostream>

template<int N>
struct NestedStruct
{
  NestedStruct<N-1> contained;
  int i;
  NestedStruct<N>() : i(N) {}
};

template<>
struct NestedStruct<0> 
{
  int i;
  NestedStruct<0>() : i(0) {}
};

int main()
{
  NestedStruct<10> f;
  int *array = reinterpret_cast<int*>(&f);
  for(unsigned int i=0;i<10;++i)
  {
    std::cout<<array[i]<<std::endl;
  }
}

Et bien sûr, vous pourriez argumenter que le tableau n'est pas initialisé au moment de la compilation (ce que je pense être impossible) mais que les valeurs qui iront dans le tableau sont calculées au moment de la compilation, et que vous pouvez y accéder comme vous le feriez avec un tableau normal... Je pense que c'est le plus proche que vous pouvez obtenir.

1 votes

Ce reinterpret_cast met en place un comportement indéfini qui déclenche l'alarme dans ma tête.

1 votes

Nous pouvons éviter reinterpret_cast en utilisant &f.i-10 ou l'ajout d'une fonction récursive int* start() à la place. Cependant, la question qui se pose est la suivante : "Le compilateur insère-t-il un remplissage entre contained y i dans la structure imbriquée". Je ne vois aucune raison pour laquelle ce serait le cas, car NestedStruct<N> y int auront les mêmes exigences d'alignement. Cependant, je ne pense pas qu'il y ait quoi que ce soit dans la spécification qui interdise l'insertion d'un padding dans ce cas. (Peut-être qu'un meilleur juriste en langues que moi en serait sûr).

2voto

danielkza Points 696

Quelque chose comme Boost.Assignment pourrait fonctionner pour les conteneurs standard. Si vous avez vraiment besoin d'utiliser des tableaux, vous pouvez l'utiliser avec Boost.Array .

2voto

Parfois (pas toujours), un tel tableau est généré à partir d'un tableau de types. Par exemple, si vous avez déjà une liste de classes variadiques (comme un modèle) et que vous voulez stocker une valeur uint32_t encapsulée, vous pouvez utiliser :

uint32_t tab[sizeof(A)]= {A::value...};

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X