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 :

Différenciation array <> container dans un template


Sujet :

Langage C++

  1. #1
    Membre Expert Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Par défaut Différenciation array <> container dans un template
    Bonjour à tous.

    J'aimerais qu'une fonction renvoie deux éléments du type et dans le type du container passé en paramètre template. Par 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
    34
    35
     
    template <typename range>
    range f(range _r[])
    {
      range r = new range[2] ;
      return r ;
    }
     
    template <typename range>
    range f(range _r)
    {
      range r = range() ;
      r.resize(2) ;
      return r ;
    }
     
    template <typename range>
    range f1(void)
    {
      range r ;
      r = f(r) ;
     
      r[0] = '1';
      r[1] = '2';
      return r;
    }
     
    int main()
    {
      int *r = f1<int*>() ;
      std::cout << r[0] << " " << r[1] << std::endl ;
     
      std::string s = f1<std::string>() ;
      std::cout << s << std::endl ;
    }
    J'essaye avec les deux premières fonctions d'isoler l'initialisation d'une "raw array" et d'un container.

    J'ai l'erreur suivante : '=' : cannot convert from 'int' to 'int *' à cette ligne-ci :
    Avez-vous d'autres techniques ou savez-vous où se trouve mon erreur ?

    Merci d'avance.

  2. #2
    Membre éprouvé
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    118
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 118
    Par défaut
    Ta question est très ambigu, tu voudrais que ta fonction template f te renvoie 2 éléments du type template spécifié et tu voudrais que ces 2 éléments soient stockées dans la variable passée en paramètre (qui est soit un tableau brut ou soit un conteneur type ceux de la STL)? ou tu préférerais que ces 2 éléments soit retournés par ta fonction(à l'aide du return)???, à la vue de ton code tu voudrais que ces 2 éléments soit retournés par la fonction avec return.

    D"un point de vue purement général sans forcément de lien avec le problème, on remarque dans ton code que le paramètre d'entrée _r de ta fonction f n'a pour seul raison d'être de permettre l'instanciation implicite de f car il n'est nullement utilisé dans le corps de la fonction. Dans ce cas, ce paramètre n'a aucune utilité, pourquoi ne pas demander une instanciation explicite de ta fonction avec le paramètre template de ta fonction f1.

    Pour revenir au véritable problème, ton code laisse présager une spécialisation partielle de ta fonction f pour les pointeurs, pointeur qui servira à contenir l'adresse du tableau alloué dynamiquement. Cependant, la spécialisation partielle de fonction template est impossible. Ainsi, une solution est de ruser en utilisant une classe template qui elle peut être spécialisée partiellement et d'y implémenter en son sein (1) une méthode statique ou encore implémenter (2) l'opérateur () (ou même une fonction membre quelconque).

    Solution (1) en tenant compte des modifications précédentes serait :
    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
    template <typename range>
    struct F
    {
        static range f()
        {
            range r = range() ;
            r.resize(2) ;
            return r;
        }
    };
     
    template <typename range>
    struct F<range*>                //spécialisation partielle de la classe F pour les pointeurs
    {
        static range* f()
        {
            return new range[2];
        }
    };
     
    template <typename range>
    range f1(void)
    {
        range r = F<range>::f();
     
        r[0] = '1';
        r[1] = '2';
        return r;
    }
     
    int main()
    {
        int* r = f1<int*>();
        std::cout << r[0] << " " << r[1] << std::endl ;
     
        std::string s = f1<std::string>() ;
        std::cout << s << std::endl ;
    }
    Solution (2) sans grand intérêt:

    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 <typename range>
    struct F
    {
        range operator()()
        {
            range r = range() ;
            r.resize(2) ;
            return r;
        }
    };
     
    template <typename range>
    struct F<range*>               //spécialisation partielle de la classe F pour les pointeurs
    {
        range* operator()()
        {
            return new range[2];
        }
    };
     
    template <typename range>
    range f1(void)
    {
        F<range> f;
        range r = f();
     
        r[0] = '1';
        r[1] = '2';
        return r;
    }
     
    int main()
    {
        int* r = f1<int*>();
        std::cout << r[0] << " " << r[1] << std::endl ;
     
        std::string s = f1<std::string>() ;
        std::cout << s << std::endl ;
    }

  3. #3
    Membre Expert Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Par défaut
    Merci pour cette solution, effectivement j'essayais de faire quelque chose d'impossible. J'ai une autre question bonus : pourquoi la spécialisation partielle de template de fonction est interdite ?

  4. #4
    Membre Expert

    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 : 34
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Par défaut
    Bonsoir,

    Pour ton erreur, dans f1<int*>, rang == int*, ainsi f(r) déduit le range de f à int (utilisation de la première surcharge, elle est plus "spécialisée"), et ainsi f(r) te retourne un int qui tu tentes de stocker dans un int*.

    Il y a un problème dans ce que tu veux faire, le concept de range n'est pas fait pour qu'on puisse nécessairement crééer un range d'un type de range déjà existant, c'est fait pour être traversé.

    Regardes n'importe quel algortihme travaillant avec les ranges ou même les itérateurs, aucun ne retourne un range du type d'entrée. Quand l'objectif est de sortir un nouveau conteneur l'algorithme demande en entrée un OutPutIterator qu'il va utiliser pour remplir la sorti commeil veut (et en général il retourne un OutPutIterator indiquant la fin de la séquence de sortie).

    En général tu n'as pas à différencier le comportement pour les différents conteneurs directement dans les signatures des fonctions, c'est plus flexibles via l'utilisation de traits/politiques.

  5. #5
    Membre Expert Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Par défaut
    Bonsoir Flob90.

    Votre avis est très intéressant et j'hésite sur la façon de procéder. En réalité, j'ai une collection de fonctions qui peuvent retourner soit seulement un caractère ( dans ce cas, un itérateur de sortie pourrait sembler "lourd") ou alors une collection de ces caractères.

    Je pourrais alors n'utiliser un itérateur de sortie que lorsque le retour est de plus d'un caractère.

    Ne trouvez-vous pas que cela brise un peu la logique générale ? Je veux dire que c'est plus agréable d'avoir un ensemble de fonction qui ont la même en-tête que des en-têtes différentes. Malgré tout, je me pose ce genre de questions car c'est la première fois que je suis exposé au problème, alors soyez indulgent

    Qu'en pensez-vous ?

  6. #6
    Membre Expert

    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 : 34
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Par défaut
    Connais tu la taille de l'ensemble retourner par la fonction avant d'appeler celle-ci (ou un majorant acceptable) ? En fonction de la tailler de la séquence d'entrée par exemple. Si c'est le cas tu peux en effet passer en paramètre un itérateur de sortie, sinon ca risque d'être assez innefficase.

    Si tu peux déterminer la taille, ca ne pose pas de problème de n'avoir qu'un seul élément dans l'ensembe de sortie, dans ce cas tu passes comme itérateur de sortie un pointeur.

    La solution la plus simple me semble quand même de retourner un conteneur le mieux adapter aux besoins (à déterminer) pour représenter l'ensemble de sortie, mais pas nécessairement le type du range d'entrée. A moins que déterminer un conteneur le mieux adapté ne soit pas envisageable ? (ie changeant selon la situation)

  7. #7
    Membre Expert Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Par défaut
    La taille est effectivement fixe et connue à la compilation. Elle sera de 1 ou de 2, et suivant l'évolution de la bibliothèque peut-être un petit peu plus (3 ou 4..).

    Je trouvais ça plus intuitif d'avoir le même type de sortie que celui d'entrée.

    Je pense que je vais laisser ça comme ça, et je verrai bien ce que la review dira...

    Mais il n'empêche que je trouve ça étrange et presque synonyme d'un problème de conception un itérateur de sortie qui n'est utilisé que pour stocker une valeur...

    Merci de vos suggestions.

  8. #8
    Membre Expert

    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 : 34
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Par défaut
    Le problème c'est que si je te mets en argument un conteneur passé à travers plusieurs adaptor de boost::range et/ou d'adaptor perso, ca pas certain que le type soit default-constructible et/ou que tu puisses insérer des éléments, et quand bien même ca serait le cas, es-tu certain que ca aurait toujours un sens ?

    Tu pourrais te faire un type perso qui te permet de retourner 1 ou 2 valeurs, ou en passant par boost quelque chose comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    boost::compressed_pair<value,boost::optional<value>

  9. #9
    Membre Expert Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Par défaut
    Je trouve que ça déstabilise un type perso. Enfin bref, je me suis décidé et finalement je vais faire un retour simple pour les valeurs à 1 élément et un iterateur de sortie pour ceux de plus de une valeur.

    Merci de votre aide et bonne soirée

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

Discussions similaires

  1. [DreamWeaver]Les liens dans ma template .dwt
    Par mamiberkof dans le forum Dreamweaver
    Réponses: 2
    Dernier message: 14/04/2006, 18h12
  2. [ Swing ] Ajout de Container dans un autre Container
    Par Invité dans le forum AWT/Swing
    Réponses: 11
    Dernier message: 16/02/2006, 15h57
  3. Query Contains dans Full-Text qui ne retourne pas de valeurs
    Par icebe dans le forum MS SQL Server
    Réponses: 1
    Dernier message: 08/02/2006, 14h04
  4. [XSL] Passage de variable dans un template
    Par Otarie dans le forum XSL/XSLT/XPATH
    Réponses: 2
    Dernier message: 14/11/2005, 23h50
  5. cast dans un template
    Par olivic dans le forum Langage
    Réponses: 15
    Dernier message: 20/10/2004, 14h10

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