Bienvenue, Invité. Merci de vous connecter ou de vous inscrire.
Avez-vous perdu votre e-mail d'activation ?

Auteur Sujet: Problème de métaprogrammation  (Lu 2412 fois)

0 Membres et 1 Invité sur ce sujet

Excellium

  • Jr. Member
  • **
  • Messages: 70
    • Voir le profil
Problème de métaprogrammation
« le: Février 27, 2013, 05:09:44 pm »
Bonjour à tous,

Je ne sais pas si c'est possible, mais j'essaye actuellement de créer un gestionnaire de ressources sous la forme d'une classe template variadique, possédant une méthode templatisée de création d'une ressource d'un type donné, permettant grâce à une expression constante et une assertion statique de vérifier si le type de ressource spécifié est autorisé par la classe (en le comparant aux types du template variadique) et d'interrompre la compilation dans le cas contraire.

Le problème est que je sèche sur le code de la méthode de vérification du type de ressource.
Voici un bout de code (simplifié) pour vous donner une idée :


template<typename... Types>
class Manager
{
public:

   template<typename Type, typename... Arguments>
   size_t create(Arguments... arguments)
   {
      static_assert(testTypes<Type>(), "Template function does not allow this type !");

      Type* ptr = new Type(Arguments...);
      ...

      return nextId();
   }

   template<typename Type>
   constexpr bool testTypes(); // méthode de vérification du type de ressource

  size_t nextId()
  {
      static size_t id;
      return id++;
  }

   ...
};

typedef Manager<sf::Texture, sf::Font, sf::SoundBuffer> ResourceManager;

ResourceManager resources();
resources.create<sf::Texture>(); // Compilation OK
resource.create<sf::Sprite>(); // Compilation ERROR
 

J'ai quelques pistes pour le code de la méthode testTypes() :

- Pour obtenir le nombre de type passés en template j'utilise -> sizeof...(Types)
- Pour vérifier que deux types sont les mêmes j'utilise -> std::is_same<Type1, Type2>
- Je peut normalement décompresser Types avec l'opérateur ... -> Types...

Maintenant il reste à créer une boucle en méta-programmation (je sais pas si c'est possible),
afin de balayer les types grâce au code :


template <int N, typename... Args> struct ElementType;
 
template <int N, typename T, typename... Args>
struct ElementType<N, T, Args...> {
        static_assert(N < sizeof...(Args) + 1, "overflow!");
        typedef typename elementType<N - 1, Args...>::type type;
};
 
template <typename T, typename... Args>
struct ElementType<0, T, Args...> {
        typedef T type;
};

// Par exemple :

elementType<1, sf::Texture, sf::Font, sf::SoundBuffer>::type>::value // donnera le type sf::Font
 

J'espère que je suis assez clair, et désolé par avance sinon, le sujet est assez difficile je trouve...  :-\



« Modifié: Février 27, 2013, 05:14:41 pm par Excellium »
"Everything should be made as simple as possible, but not simpler."

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : Problème de métaprogrammation
« Réponse #1 le: Février 27, 2013, 06:28:12 pm »
Moi je ne comprends pas pourquoi tu as besoin de vérifier explicitement le type. Si tu ne fais rien, il y a forcément un moment où ça va de toute façon produire une erreur de compilation, parce que rien n'est prévu pour le type donné (genre le stockage dans un conteneur, normalement ton manager n'en aura pas si le type n'a pas été prévu, non ?).

Ensuite, le manager multi-type template, c'est un bon exercice de contorsion mentale (un peu moins en C++11), mais à part ça je doute un peu de son utilité dans la vraie vie ;)
Laurent Gomila - SFML developer

Excellium

  • Jr. Member
  • **
  • Messages: 70
    • Voir le profil
Re : Problème de métaprogrammation
« Réponse #2 le: Février 27, 2013, 07:31:40 pm »
Il n'y a pas forcément un moment où ça va coincer, en tout cas pas si on appelle pas de fonctions membres.
On pourrait très bien créer un manager avec divers types gérés qui n'auraient pas de base commune (sf::Texture, sf::Font, sf::SoundBuffer par exemple).
En résumé, on aurait là une classe conteneur de certains types autorisés, avec un erreur à la compilation si on ose outrepasser cette restriction. De cette classe qui factorise une bonne partie du code, on pourraient dériver des classes managers plus complexes, dès lors qu'on aurait une méthode commune, telle qu'un gestionnaire audio (méthodes de contrôle), ou un gestionnaire de graphe de scene (méthode de rendu).
Tout ça c'est plus par curiosité qu'autre chose, et c'est un bon entraînement pour comprendre les subtilité de la nouvelle norme.
"Everything should be made as simple as possible, but not simpler."

nicooomg

  • Jr. Member
  • **
  • Messages: 66
    • Voir le profil
Re : Problème de métaprogrammation
« Réponse #3 le: Février 28, 2013, 09:43:34 am »
Pour contourner un problème assez similaire, j'ai créer une classe qui puisse englober n'importe quelle ressource (qui se charge !) SFML

template<class S>
class MemoryRessource
{
public:
    /// Loads a ressource from memory, and saves its offset
    MemoryRessource(const long offset, const std::vector<char>& bytes) :
        m_offset(offset),
        m_buffer(),
    {
        if(!m_buffer.loadFromMemory(&bytes[0], bytes.size()))
        {
            throw std::logic_error("Could not load data from memory");
        }
    }
    ~MemoryRessource()
    {
        /// Nothing to delete, m_buffer will be destroyed automatically
    }

    /// Returns the ressource (ie: sf::Texture)
    inline S& get() { return m_buffer; }
    /// Returns the ressource's offset
    inline const long getOffset() const { return m_offset; }

protected:
    MemoryRessource() {  }

private:
    long m_offset;
    S m_buffer;
};

Le tout, dans un manager:
template<class S>
class Memory
{
public:
/* pleins de fonctions inutiles ici :D */

    /// Accessing the ressource
    inline S& getRessource(const unsigned long key) { return m_loaded[key]->get(); }

private:
    std::map<unsigned long, std::shared_ptr<MemoryRessource<S>>> m_loaded;
};
 

Tu peux aussi bien ajouter une classe abstraite à Memory, et comme ca tu auras un type global pour chaque manager de ressources.