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 :

Template de fonction en argument d'un template de fonction


Sujet :

C++

  1. #1
    Membre éclairé
    Inscrit en
    Décembre 2010
    Messages
    290
    Détails du profil
    Informations forums :
    Inscription : Décembre 2010
    Messages : 290
    Points : 719
    Points
    719
    Par défaut Template de fonction en argument d'un template de fonction
    Bonjour !

    J'ai un code similaire à ceci :
    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
     
    /*
    	main.cpp
    */
     
    #include <iostream>
    #include <vector>
     
    template<typename T, typename F>
    void	FairePourTous (const std::vector<T>& vec, F f)
    {
    	std::vector<T>::const_iterator	it;
    	for (it=vec.begin(); it!=vec.end(); it++)
    		f (*it);
    }
     
    void	Afficher (int x)
    {
    	std::cout << x << "\n";
    }
     
    int main (int argc, char **argv)
     
    {
    	std::vector<int>	monvector;
     
    	monvector.push_back (1);
    	monvector.push_back (2);
    	monvector.push_back (3);
     
    	FairePourTous (monvector, Afficher);
     
    	return 0;
    }
    qui fonctionne très bien.
    Cependant, j'aimerais faire une version template de "Afficher", tout simplement parce que je ne peux pas savoir à l'avance ce que va contenir mon vecteur.
    D'instinct, je modifie donc mon code pour qu'il ressemble à qqchose comme ça :
    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
     
    /*
    	main.cpp
    */
     
    #include <iostream>
    #include <vector>
     
    template<typename T, typename F>
    void	FairePourTous (const std::vector<T>& vec, F f)
    {
    	std::vector<T>::const_iterator	it;
    	for (it=vec.begin(); it!=vec.end(); it++)
    		f (*it);
    }
     
    template<typename T>
    void	Afficher (T x)
    {
    	std::cout << x << "\n";
    }
     
    int main (int argc, char **argv)
     
    {
    	std::vector<int>	monvector;
     
    	monvector.push_back (1);
    	monvector.push_back (2);
    	monvector.push_back (3);
     
    	FairePourTous (monvector, Afficher);
     
    	return 0;
    }
    Et là, je me fais gronder par mon compilateur (VS2010), qui me signale qu'on ne peut pas passer un template de fonction en paramètre à un template de fonction :
    error C2896: 'void FairePourTous(const std::vector<T> &,F)' : cannot use function template 'void Afficher(T)' as a function argument
    Au sujet de cette erreur, la doc en ligne du compilateur est aussi intéressante à lire que l'annuaire, parce qu'elle dit juste comment reproduire le problème (youpi!).
    J'ai remarqué que si je précise, à l'appel de FairePourTous, que je veux une version int de Afficher (Afficher<int>) ça marche. Mais j'aimerais trouver une façon plus automatique de faire ça, parce que dans le contexte original, mon template prend qqchose comme 3 ou 4 arguments, et je ne VEUX pas les préciser à chaque fois.
    Des suggestions ?

    merci d'avance !!!

    Edit : je tiens à préciser que j'ai essayé ceci, qui me parait pourtant suffire à expliquer mes intentions à mon despotique compilateur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    template<typename T, typename F>
    void	FairePourTous (const std::vector<T>& vec, F f)
    {
    	std::vector<T>::const_iterator	it;
    	for (it=vec.begin(); it!=vec.end(); it++)
    		f<T> (*it);
    }

  2. #2
    Membre averti Avatar de Nogane
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    241
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 241
    Points : 323
    Points
    323
    Par défaut
    Bonjour,
    Une solution est de transformer Affichier en foncteur, avec un 'operator()' template:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    struct Afficher
    {
      template<typename T>
      void	operator()(T x)
      {
    	  std::cout << x << "\n";
      }
    };

  3. #3
    Membre éprouvé

    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    533
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 533
    Points : 1 086
    Points
    1 086
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    template<typename T, template <typename> class F>
    void	FairePourTous (const std::vector<T>& vec, F<T> f)
    {
    	typename std::vector<T>::const_iterator	it;
    	for (it=vec.begin(); it!=vec.end(); it++)
    		f(*it);
    }
    Peut-être comme ça ?

  4. #4
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 159
    Points
    3 159
    Par défaut
    Bonjour

    Tu utilises le mécanisme appelé la résolution de Koenig. Ce mécanisme fonctionne si les arguments passés à la fonction sont spécialisés. En revanche, la signature de ta fonction template ne peut pas spécialiser les arguments, la résolution ne fonctionne que dans un sens !

    Néanmoins, tu peux ruser ainsi pour utiliser ce mécanisme (j'ai remplacé FairePourTous par std::for_each pour alléger mais ça marche aussi j'ai testé) :

    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
    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <type_traits>
     
    template<typename T> void	Afficher (T x)
    {
    	std::cout << x << "\n";
    }
     
    template<typename T>
    void(*GetAffichageFunc(const std::vector<T>& vec))(T)
    {
    	return &Afficher<T>;
    }
     
    int main (int argc, char **argv)
     
    {
    	std::vector<int>	monvector; 
    	monvector.push_back (1);
    	monvector.push_back (2);
    	monvector.push_back (3);
      std::for_each(monvector.begin(), monvector.end(), GetAffichageFunc(monvector));
    	return 0;
    }
    D'une manière générale, je te recommande d'utiliser des classes de traits pour bien gérer tes types. Mon astuce fonctionne mais ça peut vite devenir bordélique.

    Edit : La solution de Nogane est bien et plus propre que mon example, j'ai honte de ne pas te l'avoir proposée. En effet, elle permet de ne pas relier le foncteur au type vector (et donc de l'utiliser avec n'importe quel type de collection). L'appel serait alors :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::for_each(monvector.begin(), monvector.end(), Afficher());

  5. #5
    Membre éclairé
    Inscrit en
    Décembre 2010
    Messages
    290
    Détails du profil
    Informations forums :
    Inscription : Décembre 2010
    Messages : 290
    Points : 719
    Points
    719
    Par défaut
    C'est chouette de poser un problème le soir avant de quitter le bureau et de découvrir les solutions proposées le matin en buvant son café. Merci pour vos réponses.

    Nogane : Excellent, j'avais pas pensé à utiliser un template de fonction membre.
    Très bonne méthode, merci beaucoup.

    Cob59 : L'idée parait bonne, mais le problème est le même, j'obtiens une erreur C2896 parce que je passe une fonction template en argument d'une autre fonction template, même si finalement le template est spécialisé par la signature de la fonction appelée.

    jblecanard : Excellente astuce, très simple à comprendre. Elle me servira surement une autre fois. Merci aussi pour la suggestion de std::for_each(), je pense jamais à lui.

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

Discussions similaires

  1. Réponses: 1
    Dernier message: 29/05/2014, 11h50
  2. template & passage de fonction en argument
    Par clement.analogue dans le forum Langage
    Réponses: 4
    Dernier message: 23/05/2011, 01h40
  3. Template C++ constructeur avec arguments
    Par oc_alex86 dans le forum Débuter
    Réponses: 6
    Dernier message: 06/11/2010, 15h45
  4. Réponses: 9
    Dernier message: 10/05/2010, 22h35
  5. Réponses: 11
    Dernier message: 04/10/2007, 18h18

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