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

Langage C++ Discussion :

problème méthode template


Sujet :

Langage C++

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    301
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 301
    Points : 345
    Points
    345
    Par défaut problème méthode template
    Bonjour à tous,

    J'ai un problème d'utilisation de fonction template:
    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
     
    #include <iostream>
    #include <vector>
     
    template<const char* msg> void f()
    {
    	std::cout << msg << std::endl;
    }
     
    template<int msg> void g()
    {
    	std::cout << msg << std::endl;
    }
     
    int main()
    {
    	const int i=10;
    	g<0>();
    	g<i>();
    	const char* toto = "Toto";
    	f<toto>();
    	f<"Toto">();
    	return 0;
    }
    Je ne comprend pas bien pourquoi g<0>() et g<i>() compilent alors que f<toto>() me renvoie:
    error C2971: 'f' : paramètre de modèle 'msg' : 'toto' : une variable locale ne peut pas être utilisée comme argument sans type
    et que f<"Toto">() me renvoie
    error C2762: 'f' : expression non valide comme argument de modèle pour 'msg'
    PS: j'utilise Visual2003 comme compilateur

  2. #2
    Membre confirmé

    Inscrit en
    Août 2007
    Messages
    300
    Détails du profil
    Informations forums :
    Inscription : Août 2007
    Messages : 300
    Points : 527
    Points
    527
    Par défaut
    Je pense qu'il s'agit d'un problème de compréhension du principe même des templates. Les déclarations template ne sont en effet pas comparables aux déclarations d'arguments d'une fonction, en particulier leur type est inconnu (le cas particulier de int est probablement ce qui vous induit en erreur).
    Je vous conseille de jeter un coup d'œil à la FAQ.

  3. #3
    Membre habitué
    Inscrit en
    Avril 2008
    Messages
    155
    Détails du profil
    Informations forums :
    Inscription : Avril 2008
    Messages : 155
    Points : 158
    Points
    158
    Par défaut
    Bon j'imagine que c'est pour l'exemple, mais l'utilité des template est la généricité en regroupant g() et f() en une même fonction.

    Pour que celle la marche, il faudrait :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    template<string msg> void g()
    {
    	std::cout << msg.c_str() << std::endl;
    }
    Pour l'autre, je dirais que si tu fais plutôt:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    const char* toto[] = "Toto";
    	f<toto>();
    ça peut marcher

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    301
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 301
    Points : 345
    Points
    345
    Par défaut
    Effectivement, c'est pour l'exemple, j'avais déjà tenté un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    template<std::string msg> void g()
    {
    	std::cout << msg.c_str() << std::endl;
    }
    mais le compilateur me rappelle à l'ordre avec
    error C2993: 'std::string' : type non conforme pour le paramètre de modèle sans type 'msg'
    après, pour ac_wingless mon but n'est pas ici d'utiliser les templates avec des types générique mais de les utiliser avec des valeurs (ce qui implique que ces dites valeurs doivent être connues à la compilation) un peu comme pour la métaprogrammation template.
    C'est justement à cause du fait que les valeurs doivent être connues à la compilation que le code suivant ne compile pas:
    mais je m'étais dit qu'avec une chaine de caractères constante, ça pouvait passer... mais plus ça va et plus je me dit que ce principe n'est valable qu'avec les types de base (a la compilation avec une string constante initialisée : std::string toto ("toto"); ca passe pas)

  5. #5
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Les arguments non types de templates ne peuvent prendre que des types limités.
    A template-argument for a non-type, non-template template-parameter shall be one of:
    — an integral constant expression; or
    — the name of a non-type template-parameter; or
    — the address of an object or function with external linkage, including function templates and function template-ids but excluding non-static class members, expressed as & id-expression where the & is optional if the name refers to a function or array, or if the corresponding template-parameter is a reference; or
    — a constant expression that evaluates to a null pointer value (4.10); or
    — a constant expression that evaluates to a null member pointer value (4.11); or
    — a pointer to member expressed as described in 5.3.1.
    [ Note: A string literal (2.13.4) does not satisfy the requirements of any of these categories and thus is not an acceptable
    template-argument. [ Example:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    template<class T, char* p> class X {
    X();
    X(const char* q) { /* ... */ }
    };
    X<int, "Studebaker"> x1; // error: string literal as template-argument
    char p[] = "Vivisectionist";
    X<int,p> x2; // OK
    —end example ] —end note ]

  6. #6
    Membre confirmé

    Inscrit en
    Août 2007
    Messages
    300
    Détails du profil
    Informations forums :
    Inscription : Août 2007
    Messages : 300
    Points : 527
    Points
    527
    Par défaut
    Non loicounet, les paramètre non type ne peuvent être que des entiers (avec leurs variations enum et bool), ou des pointeurs dans certaines conditions très strictes, mais jamais des classes comme std::string. Par exemple, sous VC, il faut que les pointeurs soient évaluables à des constantes à la compilation, et en plus il doit respecter des propriété d'édition de lien qui font que toutes les instanciations des différents .cpp font référence à la même classe...
    Je n'ai jamais rencontré d'utilisation légitime de paramètre non-type non-entier (ce qui comprend les enum et bool...), car même pour différentier deux instances de types incompatibles (par exemple basé sur un UUID différent), il suffit de récupérer un entier.
    Il me semble d'après le code que le principe de programmation générique est mal compris, car les arguments de l'exemple sont de simples arguments de fonction, sans généricité de type.

  7. #7
    Membre confirmé

    Inscrit en
    Août 2007
    Messages
    300
    Détails du profil
    Informations forums :
    Inscription : Août 2007
    Messages : 300
    Points : 527
    Points
    527
    Par défaut
    OK CedricMocquillon je comprends mieux... Je ne suis pas sûr que le C++ sous sa forme VC soit bien adapté à cette utilisation.

  8. #8
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    301
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 301
    Points : 345
    Points
    345
    Par défaut
    Ok merci JolyLoic par contre un dernier détail, je ne comprend pas bien pourquoi dans l'exemple suivant:
    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
    #include <iostream>
     
    template<char* msg> void f()
    {
    	std::cout << msg << std::endl;
    }
     
    char toto[] = "Toto";
     
    int main()
    {
    	char l_toto[] = "Toto local";
    	f<toto>();
    	f<l_toto>();
    	return 0;
    }
    f<toto>() compile mais pas f<l_toto>() :
    error C2971: 'f' : paramètre de modèle 'msg' : 'l_toto' : une variable locale ne peut pas être utilisée comme argument sans type
    et il me met exactement le même message si je déclare l_toto de la manière suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     const char l_toto[] = "Toto local";
    pourtant dans ce cas ça ressemble bien au cas
    an integral constant expression
    PS: pour la petite histoire, je me suis posé cette question à cause de l'exemple suivant:
    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
    class Exception : public std::exception
    {
    public:
        Exception(std::string Msg)
        {
            _sMsg = Msg;
        }
     
        virtual ~Exception() throw()
        {
        }
     
        virtual const char * what() const throw()
        {
            return _sMsg.c_str();
        }
     
    private:
        std::string _sMsg;
    };
     
    class NullPointerException : public Exception
    {
    public:
    	NullPointerException () : Exception("null pointer")
    	{}
    };
    et je voulais faire un truc du genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    template<const char* msg>
    struct ExceptionBase : public std::exception
    {
    	const char* what() const throw()
        {
            return msg;
        }
    };
     
    typedef  ExceptionBase<"Error : null pointer"> NullPointerException;
    ce qui ne compile pas alors que le code suivant compile:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    template<const char* msg>
    struct ExceptionBase : public std::exception
    {
    	const char* what() const throw()
        {
            return msg;
        }
    };
     
    const char* npe = "Error : null pointer";
     
    typedef  ExceptionBase<npe> NullPointerException;

  9. #9
    Membre habitué
    Inscrit en
    Avril 2008
    Messages
    155
    Détails du profil
    Informations forums :
    Inscription : Avril 2008
    Messages : 155
    Points : 158
    Points
    158
    Par défaut
    Bon j'imagine que c'est pour l'exemple, mais l'utilité des template est la généricité en regroupant g() et f() en une même fonction.
    Je disais ça==>
    regrouper en

    template<class T> void g()
    Je n'ai pas testé le string dont je parlais mais je l'aurais écrit comme ci-dessus.
    Juste filé un bout de code pour donner des idées...

    bref!

  10. #10
    Membre chevronné
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    904
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 904
    Points : 1 922
    Points
    1 922
    Par défaut
    Si j'ai bien compris ce qui a été dit plus haut, c'est parce-que ici
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    typedef  ExceptionBase<"Error : null pointer"> NullPointerException;
    tu passe une constante littérale en paramètre au template, alors que là
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    const char* npe = "Error : null pointer";
     
    typedef  ExceptionBase<npe> NullPointerException;
    tu passes un pointeur constant (i.e : un entier) en paramètre au template.

  11. #11
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    301
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 301
    Points : 345
    Points
    345
    Par défaut
    Désolé, je n'avais pas copié le bon code. C'est celui là qui compile:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    char npe[] = "Error : null pointer";
    typedef  ExceptionBase<npe> NullPointerException;
    alors que le précédent ne compile pas

  12. #12
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    301
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 301
    Points : 345
    Points
    345
    Par défaut
    au final :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    const char* npe0 = "Error : null pointer";
    char* npe1 = "Error : null pointer";
    char npe2[] = "Error : null pointer";
    const char npe3[] = "Error : null pointer";
     
    typedef  ExceptionBase<"Error : null pointer"> NullPointerException0;	//ne compile pas
    typedef  ExceptionBase<npe0> NullPointerException1;			//ne compile pas
    typedef  ExceptionBase<npe1> NullPointerException2;			//ne compile pas
    typedef  ExceptionBase<npe2> NullPointerException3;			//compile
    typedef  ExceptionBase<npe3> NullPointerException4;			//ne compile pas

  13. #13
    Membre chevronné
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    904
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 904
    Points : 1 922
    Points
    1 922
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char npe[] = "Error : null pointer";
    Un tableau c'est un pointeur constant sur le premier objet du tableau (en d'autres termes, sa valeur ne peut changer).

    Et ça ça marche ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    char * const npe4 = "Erreur : null pointeur"; // Pointeur constant sur variable
    char const * const npe5 = "Erreur : null pointeur"; // Pointeur constant sur constante
    Par contre c'est celui-là qui m'étonne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    const char npe3[] = "Error : null pointer";
    typedef  ExceptionBase<npe3> NullPointerException4;			//ne compile pas

Discussions similaires

  1. Réponses: 10
    Dernier message: 08/06/2012, 09h22
  2. Réponses: 5
    Dernier message: 30/08/2010, 18h26
  3. [xslt][Javascript] Problème de templates
    Par Dnallabar dans le forum XSL/XSLT/XPATH
    Réponses: 2
    Dernier message: 03/11/2005, 11h55
  4. problème classes templates...
    Par youp_db dans le forum C++
    Réponses: 3
    Dernier message: 02/11/2005, 13h04
  5. Réponses: 3
    Dernier message: 22/03/2005, 09h13

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