IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

specialisation partielle de template recursif


Sujet :

C++

  1. #1
    Membre à l'essai
    Inscrit en
    Février 2010
    Messages
    27
    Détails du profil
    Informations forums :
    Inscription : Février 2010
    Messages : 27
    Points : 24
    Points
    24
    Par défaut specialisation partielle de template recursif
    Bonjour, je ne suis encore très à l'aise avec les templates, donc j'aurais besoin de vos lumières pour résoudre mon problème de compile.

    Le but du jeu est de créer une fonction xorand qui prend deux tableaux (v1,v2) de type T et de taille N, et calcule le xor de tous les éléments de v1&v2. Sans "templatiser" le type des tableaux ça marchait bien, mais depuis que j'ai rajouté le typename T, rrien ne va plus.

    Voici le code fautif :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    template<typename T,int N> T inline xorand(T* v1, T* v2)
    {
    	return xorand<T,N/2>(v1, v2) ^ xorand<T,N-N/2>(v1+N/2, v2+N/2);
    }
    // Spécialisation pour N=1
    template<typename T> T inline xorand<T,1>(T* v1, T* v2)
    {
    	return v1[0] & v2[0];
    }
    Merci.

  2. #2
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    On ne peut pas faire de spécialisation partielle de fonction (de toute façon préférer la surcharge). Il vaut donc mieux passer par des structures :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    template<int N>
    struct xorand
    {
    template<typename T> T operator()(T* v1, T* v2)
    {
    	return xorand<N/2>()(v1, v2) ^ xorand<N-N/2>()(v1+N/2, v2+N/2);
    }
    };
    // Spécialisation pour N=1
    template<>
    struct xorand<1>
    {
    template<typename T> T operator()(T* v1, T* v2)
    {
    	return v1[0] & v2[0];
    }
    };
     
     
    int main()
    {
        xorand<10>()((int*)0,(int*)0);
    }
    Edit : un petit tuto : La meta-programmation en C++

  3. #3
    Membre expert

    Avatar de germinolegrand
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Octobre 2010
    Messages
    738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Octobre 2010
    Messages : 738
    Points : 3 892
    Points
    3 892
    Par défaut
    Bonjour !
    Je vais me permettre de corriger le code de 3DArchi qui m'a piqué les yeux à première vue :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
     
    template <class T, int N>
    struct Xoa
    {
    	inline static T xorand(T* v1, T* v2)
    	{
    	    return Xoa<T,N/2>::xorand(v1, v2) ^ Xoa<T,N-N/2>::xorand(v1+N/2, v2+N/2);
    	}
    };
     
    template <class T>
    struct Xoa<T, 1>
    {
    	inline static T xorand(T* v1, T* v2)
    	{
    	    return v1[0] & v2[0];
    	}
    };
     
    //fonction libre facultative, pour la simplicité d'utilisation
    template <int N, class T>
    inline T xorand(T* v1, T* v2)
    {
        return Xoa<T,N>::xorand(v1,v2);
    }
     
    int main()
    {
        std::cout << "Hello world!" <<std::endl;
     
        std::vector<unsigned int> v1, v2;
     
        Xoa<unsigned int,10>::xorand(v1.data(),v2.data());
        xorand<10>(v1.data(), v2.data());//version facultative mais qui ne demande pas de préciser le type
     
        //vector::data() est C++11, on peut remplacer par &v[0] en C++03
     
        return 0;
    }
    Lorsqu'on ajoute des classes juste pour utiliser leurs fonctions, il faut déclarer ces dernières statiques. Cela évite de construire un objet à chaque itération et permet au compilateur d'inliner tout le calcul.

    Comme précisé dans le code, j'ai ajouté une fonction libre pour faciliter l'utilisation et surtout éviter de préciser T à l'appel. Celle-ci est facultative mais recommandée car elle ne coûte pas plus cher.

    J'aurais tendance à éviter les operator() en programmation générique car cela obscurcit le code au possible.

  4. #4
    Membre éclairé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Points : 764
    Points
    764
    Par défaut
    On peut aussi émuler la spécialisation d'une fonction grâce à la surcharge en introduisant un type intermédiaire. Un exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    #include <iostream>
     
    // Structure intermediaire, n'est pas exposée à l'utilisateur
    template<typename, int> struct xorand_dummy {};
    // Version générale
    template<int N, typename T> T inline xorand_(T* v1, T* v2, xorand_dummy<T,N>*)
    {
    	return xorand_(v1, v2, (xorand_dummy<T,N/2>*)0) ^ xorand_(v1+N/2, v2+N/2, (xorand_dummy<T,N-N/2>*)0);
    }
    // Spécialisation pour N=1
    template<typename T> T inline xorand_(T* v1, T* v2, xorand_dummy<T,1>*)
    {
    	return v1[0] & v2[0];
    }
    // Fonction appelée par l'utilisateur
    template<int N, typename T> T inline xorand(T* v1, T* v2)
    {
    	return xorand_(v1, v2, (xorand_dummy<T,N>*)0);
    }
     
    int main()
    {
    	int t1[6], t2[6];
    	for (size_t i = 0; i < 6; ++i)
    	{
    		t1[i] = i; t2[i] = 3*i;
    	}
     
    	std::cout << xorand<6>(t1, t2) << std::endl;
    	std::cout << xorand<1>(t1, t2) << std::endl;
     
    	return 0;
    }
    C'est parfois plus clair que la méthode du foncteur. Au niveau performance, je ne sais pas ce qui sera le mieux. J'imagine que le compilateur ne doit pas avoir trop de mal à éliminer le superflu dans les deux cas, mais pour être sûr il faudrait faire un comparatif sur tes données.

  5. #5
    Membre expert

    Avatar de germinolegrand
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Octobre 2010
    Messages
    738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Octobre 2010
    Messages : 738
    Points : 3 892
    Points
    3 892
    Par défaut
    Par contre ça ne m'a vraiment pas l'air plus clair que la méthode statique... C'est plus long, plus complexe, moins optimisé...

  6. #6
    Membre éclairé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Points : 764
    Points
    764
    Par défaut
    Tu es bien dur... Pour ce qui est de la taille du code, ça ne saute pas aux yeux, et pour les performances, je ne jugerai pas avant d'avoir vu une mesure sur des données réelles. Mais c'est plus complexe, oui.

    Quoi qu'il en soit, je voulais surtout signaler qu'on peut faire autrement, et que "spécialisation partielle de fonction template" ne rime pas toujours avec "structure et méthodes statiques" (ou "foncteur"). Ici il faut rajouter un paramètre à la fonction pour pouvoir utiliser la surcharge, ça limite l'intérêt de la méthode je suis d'accord, mais il y a des cas où les paramètres essentiels à la fonction suffisent.

  7. #7
    Membre expert

    Avatar de germinolegrand
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Octobre 2010
    Messages
    738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Octobre 2010
    Messages : 738
    Points : 3 892
    Points
    3 892
    Par défaut
    Je suis d'accord qu'il y a plusieurs façons de faire
    Pour les perfs, la seule différence une fois compilé entre ta version et la mienne c'est ce pointeur (qui restera en debug).

  8. #8
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    La méthode de 3DArchi a quand même un avantage : c'est un foncteur polymorphique (à N fixé) qui fonctionnera avec n'importe quel bibliothèque utilisant cette notion.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 3
    Dernier message: 29/03/2009, 10h21
  2. Réponses: 4
    Dernier message: 04/09/2008, 10h58
  3. specialisation de fonction template
    Par chubinou dans le forum Langage
    Réponses: 8
    Dernier message: 13/11/2007, 14h03
  4. [XSLT] templates recursifs
    Par Kurisu dans le forum XSL/XSLT/XPATH
    Réponses: 4
    Dernier message: 08/12/2006, 13h23
  5. Réponses: 5
    Dernier message: 29/12/2005, 21h27

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo