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 valeur par défaut quelque soucis


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Juillet 2010
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2010
    Messages : 17
    Par défaut Template valeur par défaut quelque soucis
    Voici mon code :

    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
    #pragma once
     
    template <class T, int N = 3>
    class point
    {
    private:
    	T tab[N];
    public:
    	point(T a = 0, T b = 0, T c = 0);
    	~point();
    	T getVal(int);
    	//T operator[](int);
    };
     
    template <class T, int N = 3>
    point<T>::point(T a = 0, T b = 0, T c = 0)
    {
    	tab[1] = a;
    	tab[2] = b;
    	tab[3] = c;
    }
     
    template <class T, int N = 3>
    point<T>::~point()
    {
    	delete tab;
    }
     
    //template <class T, int N = 3>
    //T point<T>::operator[](int i)
    //{
    //	return tab[i];
    //}
     
    template <class T, int N = 3>
    T point<T>::getVal(int i)
    {
    	return tab[i];
    }
    L'erreur que j'obtiens est :

    error C3860: template argument list following class template name must list parameters in the order used in template parameter list
    error C4519: default template arguments are only allowed on a class template

    Je pense que le problème vient du int N = 3 dans ma template. Je pense que quelque chose m'échappe dans l'utilisation des templates. Merci d'avance pour votre aide.

  2. #2
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2012
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2012
    Messages : 4
    Par défaut
    Bonjour,

    Je vais citer quelques parties du FDIS (c'est à dire, à peu près, la définition du C++), ce n'est pas très grave si tu ne comprends pas les dites citations, c'est juste pour donner des précisions.
    En plus de l'erreur que tu as donnée, il y a d'autres problèmes dans ton code.

    Précision sur les templates

    Retournons à la définition d'un template (appelé aussi patron ou modèle en français) :
    Citation Envoyé par FDIS (n3290), §14 [temp] ¶1
    A template defines a family of classes or functions or an alias for a family of types. […]
    Dans ton cas, tu définis une famille de classes point. Il se trouve que les membres de cette famille de classes ont des fonctions membres.
    Ta famille de classes point contient par exemple une classe point<int,3> et cette classe point<int,3> a une fonction membre int point<int,3>::getVal(int).

    Ton class template (c'est à dire ta famille de classe, ton modèle de classe) a une particularité : il est paramétré par un argument (que tu as appelé N) ayant une valeur par défaut (que tu as fixé à 3).
    Citation Envoyé par FDIS (n3290), §14.1 [temp.param] ¶9
    A default template-argument is a template-argument (14.3) specified after = in a template-parameter. A default template-argument may be specified for any kind of template-parameter (type, non-type, template) that is not a template parameter pack (14.5.3). A default template-argument may be specified in a template declaration. A default template-argument shall not be specified in the template-parameter-lists of the definition of a member of a class template that appears outside of the member's class. A default template-argument shall not be specified in a friend class template declaration. If a friend function template declaration specifies a default template-argument, that declaration shall be a definition and shall be the only declaration of the function template in the translation unit.
    La mise en gras est de moi on peut lire cette phrase comme :
    Un argument par défaut d'un template (3 dans ton code) ne doit pas être spécifié dans la liste de paramètre de template (<class T, int N=3> dans ton code) de la définition d'un membre d'une class template (template <class T, int N=3> T point<T>::getVal(int i){ … } dans ton code) qui apparait hors de la classe du membre (c'est à dire hors de template<class T, int N=3> class point{ … };, ce qui est le cas dans ton code).
    Donc, tu ne peut pas spécifier de valeur par défaut pour N dans le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    template <class T, int N = 3>
    T point<T>::getVal(int i)
    {
    	return tab[i];
    }
    On pourrait croire que c'est dommage, mais en fait non, parce que tu ne peux pas le faire, mais… tu n'as pas besoin de le faire.

    Citation Envoyé par FDIS (n3290), §14.5.1 [temp.class] ¶3
    When a member function, a member class, a member enumeration, a static data member or a member template of a class template is defined outside of the class template definition, the member definition is defined as a template definition in which the template-parameters are those of the class template. The names of the template parameters used in the definition of the member may be different from the template parameter names used in the class template definition. The template argument list following the class template name in the member definition shall name the parameters in the same order as the one used in the template parameter list of the member. Each template parameter pack shall be expanded with an ellipsis in the template argument list. […]
    Donc, quand tu définis une fonction membre (par exemple getVal) d'un class template (par exemple point) hors de la définition de ce class template (template <class T,int N=3> class point{ /*C'est à dire pas ici.*/ };), alors tu dois définir cette fonction membre comme un template dont les paramètres sont ceux du class template.

    La question qui se pose alors est : quels sont les paramètres de ton class template ? T et N, en effet, bien que N ait une valeur par défaut, ça reste un paramètre de ton template. La bonne définition de getVal est donc :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    template <class T, int N> // Pas de valeur par défaut à cause de §14.1 ¶9
    T point<T,N>::getVal(int i) // point a T et N comme argument à cause de §14.5.1 ¶3
    {
    	return tab[i];
    }
    Note que le même problème est présent dans tes autres fonctions membres y compris le constructeur.

    En fait, tu n'as pas besoin de spécifier de valeur par défaut parce que ce n'est pas ta fonction qui est un function template, mais ta classe. Donc quand getVal est appelé, elle l'est sur un objet qui a déjà une valeur pour N.

    Destruction d'un sous objet

    Ton class template a un membre :
    Et ton destructeur est (après correction) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    template <class T, int N>
    point<T,N>::~point()
    {
    	delete tab;
    }
    Or :
    Citation Envoyé par FDIS (n3290), §3.7.5 [basic.stc.inherit] ¶1
    The storage duration of member subobjects, base class subobjects and array elements is that of their complete object (1.8).
    C'est à dire que quand tu supprimeras un point, tu supprimeras aussi son membre tab. Tu n'as donc pas besoin d'appeler delete sur tab et à vrai dire tu ne dois pas le faire.
    En général, tu appelles delete sur les objets retournés par new. En plus dans ton code, c'est un tableau, dans ce cas on appelle new[] et delete[] quand c'est nécessaire.
    Ici, tu n'as besoin ni d'un new[], ni d'un delete[] et encore moins d'un new ou d'un delete.
    Donc finalement… tu n'as même pas besoin de définir un destructeur ! :)

    Redéfinition d'un argument par défaut d'une fonction

    La déclaration du constructeur de point est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    point(T a = 0, T b = 0, T c = 0);
    Sa définition (après correction) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    template <class T, int N>
    point<T,N>::point(T a = 0, T b = 0, T c = 0)
    {
    	tab[1] = a;
    	tab[2] = b;
    	tab[3] = c;
    }
    mais les arguments par défaut d'une fonction ne doivent être spécifiés qu'une seule fois :
    Citation Envoyé par FDIS (n3290), §8.3.6 [dcl.fct.default] ¶4
    […] A default argument shall not be redefined by a later declaration (not even to the same value). […]
    En plus il y a un cas particulier :
    Citation Envoyé par FDIS (n3290), §8.3.6 [dcl.fct.default] ¶6
    […] Default arguments for a member function of a class template shall be specified on the initial declaration of the member function within the class template. […]
    Ça veut dire que tu es obligés de mettre ces arguments par défaut dans la déclaration lors de la définition du class template.

    Accès en dehors des limites d'un tableau

    Ton constructeur est (après correction) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    template <class T, int N>
    point<T,N>::point(T a, T b, T c)
    {
    	tab[1] = a;
    	tab[2] = b;
    	tab[3] = c;
    }
    Mais que ce passe t il si N=2 ? Sachant que tu n'as pas d'autre constructeur c'est problématique si tu souhaites créer des points sur un plan (avec N=2 donc).
    Si tu souhaites conserver se constructeur mais t'assurer qu'il ne sera pas appeler pour N<3, tu peux utiliser static_assert : ça te permet de vérifier lors de la compilation si une condition est vrai :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    template <class T, int N>
    point<T,N>::point(T a, T b, T c)
    {
    	static_assert(N>=3, "Construction d'un point de moins de 3 dimensions avec trois valeurs.");
    	tab[1] = a;
    	tab[2] = b;
    	tab[3] = c;
    }
    Cela te permet de trouver les erreurs dès la compilation ! Malheureusement static_assert n'apparait qu'avec C++11 (une version de C++ sortie fin 2011), Boost possède une macro similaire et il est facile de l'écrire en C++03 pur. Mais si ce n'est qu'un code « pour tester », tu n'as pas trop à y faire attention, sache juste que c'est dangereux.
    Remarque que ce n'est tout de même pas un très beau constructeur, si tu crées un point à 4 dimensions, seul trois des quatre valeurs seront initialisées.

    Utilisation de #pragma

    Les directives préprocesseurs #pragma sont utiles si tu ne vises qu'un seul compilateur :
    Citation Envoyé par FDIS (n3290), §16.6 [cpp.pragma] ¶1
    A preprocessing directive of the form
    # pragma pp-tokensopt new-line
    causes the implementation to behave in an implementation-defined manner. The behavior might cause translation to fail or cause the translator or the resulting program to behave in a non-conforming manner.
    Any pragma that is not recognized by the implementation is ignored.
    Pour garder de bonnes habitudes il est souvent préférable d'utiliser l'include guard habituelle (avec le nom que tu veux) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    #ifndef FILENAME_HPP_INCLUDED
    #define FILENAME_HPP_INCLUDED
    // Code…
    #endif
    Version corrigée

    Voici le code corrigé, il reste tout de même quelques autres corrections à apporter (notamment sur le constructeur).
    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
    #ifndef POINT_HPP_INCLUDED
    #define POINT_HPP_INCLUDED
     
    template <class T, int N = 3>
    class point
    {
    private:
    	T tab[N];
     
    public:
    	point(T a = 0, T b = 0, T c = 0);
    	T getVal(int);
    };
     
    template <class T, int N>
    point<T,N>::point(T a, T b, T c)
    {
    	static_assert(N>=3, "Construction d'un point de moins de 3 dimensions avec trois valeurs."); // Si ton compilateur supporte C++11.
     
    	tab[1] = a;
    	tab[2] = b;
    	tab[3] = c;
    }
     
    template <class T, int N>
    T point<T,N>::getVal(int i)
    {
    	return tab[i];
    }
    #endif
    Excuses moi pour mes mauvaises traductions, je ne connais pas bien le termes français correspondant à certains termes anglais. Bonne chance !

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Juillet 2010
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2010
    Messages : 17
    Par défaut
    Woah ! Je te remercie beaucoup. Très bonne explication j'ai vraiment compris le pourquoi de mes erreurs ce qui me sera d'une forte aide pour ne plus les commettre. Merci encore pour ton temps.

    Je n'avais jamais entendu parler des static_assert. Je vais y jeter un coup d'oeil. Mais c'est vrai que mon constructeur est bancale. Mon intention était d'avoir une classe point qui peut être utiliser dans des cas en deux dimensions et d'autre en 3.

    Merci encore de ton aide

Discussions similaires

  1. Template, Smart Pointer et Valeur par défaut
    Par oxyde356 dans le forum Langage
    Réponses: 10
    Dernier message: 22/03/2011, 23h08
  2. Valeur par défaut dun DBLookupcombobox
    Par lol_adele dans le forum Bases de données
    Réponses: 2
    Dernier message: 13/05/2004, 09h08
  3. Valeur par défaut dans une table objet
    Par Ricky81 dans le forum Oracle
    Réponses: 12
    Dernier message: 18/03/2004, 11h52
  4. Réponses: 2
    Dernier message: 18/10/2003, 14h42
  5. Unique + valeur par défaut
    Par ketalie dans le forum Outils
    Réponses: 4
    Dernier message: 02/07/2003, 15h29

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