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 :

Renvoyer un bitset::reference


Sujet :

C++

  1. #1
    Membre du Club
    Homme Profil pro
    Inscrit en
    Août 2013
    Messages
    81
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Août 2013
    Messages : 81
    Points : 50
    Points
    50
    Par défaut Renvoyer un bitset::reference
    Bonjour!
    Dans une classe template possédant un std::bitset, j'essaie de surcharger l'opérateur [] afin de modifier la valeur du bitset. C'est-à-dire de pouvoir faire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    MyClass<8> foo;
    foo[7]=0;
    ce qui aura pour effet de modifier la 7ème valeur du bitset.

    L'opérateur[] de bitset renvoi un std::bitset::reference, et j'aimerai pouvoir le renvoyer aussi.

    Je me demande donc si il est possible de 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
    11
    12
    template <size_t n>
    bitset::reference MyClass<n>::operator[] (size_t i)
    {
        if(i<n && i>=0)
        {
            return m_content[i];
        }
        else
        {
            return NULL;
        }
    }
    ou si la classe reference ne peut être utilisée.

    Merci pour vos lumières!

    cordialement,

    Simac

  2. #2
    Membre émérite
    Avatar de Daïmanu
    Homme Profil pro
    Développeur touche à tout
    Inscrit en
    Janvier 2011
    Messages
    696
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur touche à tout

    Informations forums :
    Inscription : Janvier 2011
    Messages : 696
    Points : 2 438
    Points
    2 438
    Par défaut
    Bonjour.

    Je pense que la façon la plus propre quand tu accèdes à des cases en dehors du tableau, est de lancer une exception de type std::out_of_range.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include <stdexcept>
    template <size_t n>
    bitset::reference MyClass<n>::operator[] (size_t i)
    {
        if(i<n && i>=0)
        {
            return m_content[i];
        }
        else
        {
            throw std::out_of_range("Message d'erreur");
        }
    }
    Je fais appel aux esprits de Ritchie, Kernighan, Stroustrup et Alexandrescu
    Donnez moi la force, donnez moi le courage de coder proprement !

    « Ça marche pas » n'est PAS une réponse convenable, merci de détailler le souci en fournissant l’environnement, le code source, les commandes et les messages d'erreur.

    Ce club possède également un clavardage, on y trouve quelques perles entre deux sessions d'entraides.

  3. #3
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Btw, size_t est unsigned donc la moitié du test est inutile (un warning devrait te le signaler selon tes options de compilation)
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  4. #4
    Membre du Club
    Homme Profil pro
    Inscrit en
    Août 2013
    Messages
    81
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Août 2013
    Messages : 81
    Points : 50
    Points
    50
    Par défaut
    Citation Envoyé par Daïmanu Voir le message
    Je pense que la façon la plus propre quand tu accèdes à des cases en dehors du tableau, est de lancer une exception de type std::out_of_range.
    Effectivement, c'est plus sécurisé. Mais une exception n'est-elle pas sensée provoquer la fin de l'exécution du programme si elle n'est pas interceptée ? Cela signifierai qu'il faudrait un bloc try{} catch{} pour chaque appels de l'opérateur [] ?

    Citation Envoyé par Bousk Voir le message
    Btw, size_t est unsigned donc la moitié du test est inutile (un warning devrait te le signaler selon tes options de compilation)
    Rien à redire ^^

    Bien que vos réponses me soient utiles, ma question portait sur l'utilisation du type std::bitset::reference comme type de retour.
    En essayant de compiler, gcc me dit :
    `template<unsigned int _Nb> class std::bitset' used without template parameters
    ISO C++ forbids declaration of `reference' with no type
    pour la pré-déclaration de la surcharge (en public dans ma classe) :
    std::bitset::reference operator[] (size_t i);Il reconnait donc std::bitset comme étant le type, et non reference.

    Je me demande si une fonction peut retourner le type reference, et si oui, comment.

    Merci !

  5. #5
    Membre chevronné Avatar de Ehonn
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2012
    Messages
    788
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2012
    Messages : 788
    Points : 2 160
    Points
    2 160
    Par défaut
    Il ne faut pas oublier le <B> à std::bitset<B>.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    template <size_t N>
    typename std::bitset<N>::reference MyClass<n>::operator [](size_t const i)
    Tu peux ajouter : using reference = typename std::bitset<N>::reference; ou le typedef équivalent pour utiliser directement reference.

    PS : Généralement, l'opérateur [i] a un comportement indéfini si i n'est pas valide (pour des questions de performances je pense).
    Dans le cas de std::bitset, il n'y a pas de fonction at(i) comme avec std::vector mais il y a la fonction membre test.

    Edit : Ajout des typename...

  6. #6
    Membre du Club
    Homme Profil pro
    Inscrit en
    Août 2013
    Messages
    81
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Août 2013
    Messages : 81
    Points : 50
    Points
    50
    Par défaut
    En rajoutant le paramètre template à la pré-déclaration dans la classe std::bitset<n>::reference operator[] (size_t const i);, le compilo me dit
    expected `;' before "operator"
    (j'ai mal compris ce que tu voulais dire ?)

    Dans la déclaration entière de l'opérateur
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    template <size_t n>
    std::bitset<n>::reference MyClass<n>::operator[] (size_t const i)
    le compilo retourne aussi une erreur :
    expected constructor, destructor, or type conversion before "MyClass"

    Citation Envoyé par Ethonn
    Tu peux ajouter : using reference = std::bitset<N>::reference;
    Il faut donc déclarer le paramètre template N, mais comment ? Ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    template<size_t N>
    using reference = std::bitset<N>::reference;
    crée
    expected unqualified-id before "using"

    Citation Envoyé par Ethonn
    ou le typedef équivalent
    std::bitset étant template, le typedef n'est il pas impossible ? Ou alors je ne saisi pas la FAQ sur les templates...

  7. #7
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 565
    Points : 7 648
    Points
    7 648
    Par défaut
    Bonjour,

    Le type std::bitset<> doit impérativement être défini avant, ensuite
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    template<std::size_t N>
    typename std::bitset<N>::reference  MyClass<N>::operator[]( std::size_t const i )  { ... }
    devrait fonctionner s'il a bien été déclaré dans MyClass<>.

  8. #8
    Membre du Club
    Homme Profil pro
    Inscrit en
    Août 2013
    Messages
    81
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Août 2013
    Messages : 81
    Points : 50
    Points
    50
    Par défaut
    Merci, c'est bien ça, ça marche !
    (J'aimerai rajouter quelque chose parce que terminer comme ça c'est un peut fade, mais je trouve pas.) Alors, à nouveau, Merci à vous)

  9. #9
    Membre chevronné Avatar de Ehonn
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2012
    Messages
    788
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2012
    Messages : 788
    Points : 2 160
    Points
    2 160
    Par défaut
    Le <N> vient de la classe. Voici la syntaxe (avec différentes possibilités) :
    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
    40
    41
    42
    43
    44
    45
    46
    // g++ -Wall -Wextra -Wconversion -Wsign-conversion -Ofast -std=c++11 -pedantic -fopenmp main.cpp -o main && ./main
     
    #include <iostream>
    #include <bitset>
     
    template <size_t N>
    class bitset_t
    {
    public:
     
    	using reference = typename std::bitset<N>::reference;
    	// NOTE: Avec typedef
    	// typedef typename std::bitset<N>::reference reference;
     
    private:
     
    	std::bitset<N> m_bitset;
     
    public:
     
    	bitset_t() : m_bitset() { } // ou rien, ou « = default » selon l'initialisation voulue
     
    	bool operator [](size_t const i) const { return m_bitset[i]; }
     
    	reference operator [](size_t const i) { return m_bitset[i]; }
     
    	// NOTE: Si définition séparée de la déclaration
    	// reference operator [](size_t const i);
    };
     
    // NOTE: Si définition séparée de la déclaration
    // template <size_t N>
    // typename bitset_t<N>::reference bitset_t<N>::operator [](size_t const i) { return m_bitset[i]; }
     
    int main()
    {
    	bitset_t<5> b;
    	b[0] = 2;
     
    	for (size_t i = 0; i < 5; ++i)
    	{
    		std::cout << b[i] << std::endl;
    	}
     
    	return 0;
    }
    Pour l'histoire du using contre typedef. J'utilise toujours using qui est plus générique et je le trouve plus simple et plus clair (mais il s'agit d'un choix personnel, un choix de coding style).
    Seul using permet d'écrire un typedef template. Il s'agit de cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    template <class T>
    using vector_t = std::vector<T>;
    Dans le cas de ton code, le type reference n'est pas template et donc typedef fonctionne aussi.

  10. #10
    Membre du Club
    Homme Profil pro
    Inscrit en
    Août 2013
    Messages
    81
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Août 2013
    Messages : 81
    Points : 50
    Points
    50
    Par défaut
    OK, merci pour tes explications

  11. #11
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,
    Citation Envoyé par Daïmanu Voir le message
    Bonjour.

    Je pense que la façon la plus propre quand tu accèdes à des cases en dehors du tableau, est de lancer une exception de type std::out_of_range.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include <stdexcept>
    template <size_t n>
    bitset::reference MyClass<n>::operator[] (size_t i)
    {
        if(i<n && i>=0)
        {
            return m_content[i];
        }
        else
        {
            throw std::out_of_range("Message d'erreur");
        }
    }
    Tu n'as pas tord : un accès en dehors des limites représente effectivement une erreur, et devrait être considéré comme telle.

    Seulement, un accès en dehors des limites, c'est aussi (et surtout) une erreur de programmation de la part de celui qui utilise notre classe. C'est, typiquement, le genre d'erreur qui ne devrait pas pouvoir survenir en production, et qui doit être clairement indiquée en période de tests.

    Du coup, au lieu de lancer une exception (qui nous fait entrer de plein pieds dans la programmation défensive, ce qui n'est vraiment pas une bonne manière de programmer), il faudrait faire une assertion sur le fait que l'index attendu doit être cohérent par rapport avec la taille du bitset, et pour cela, nous disposons de la macro assert (au travers du fichier d'en-tête <cassert> ), ce qui nous donnerait quelque chose comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    template <size_t n>
    bitset::reference MyClass<n>::operator[] (size_t i)// le fait d'utiliser un size_t garanti que la valeur de i ne sera jamais négative
    {
        assert(i < m_content.size() && "Index out of bound"); // plantera violemment le programme en période de test si l'index est 
                                                              // plus grand ou égal à la taille en bits du bitset
                                                              // mais nous permettra de remonter la pile d'appels en mode debug
            return m_content[i];
    }
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  12. #12
    Membre émérite
    Avatar de Daïmanu
    Homme Profil pro
    Développeur touche à tout
    Inscrit en
    Janvier 2011
    Messages
    696
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur touche à tout

    Informations forums :
    Inscription : Janvier 2011
    Messages : 696
    Points : 2 438
    Points
    2 438
    Par défaut
    Bonjour.

    En effet, je n'avais pas pensé aux assertions. Mais il n'est pas mieux d'utiliser static_assert du coup, puisqu'il fait partie du langage ?
    J'imagine que ce choix dépend de tout à chacun.
    Je fais appel aux esprits de Ritchie, Kernighan, Stroustrup et Alexandrescu
    Donnez moi la force, donnez moi le courage de coder proprement !

    « Ça marche pas » n'est PAS une réponse convenable, merci de détailler le souci en fournissant l’environnement, le code source, les commandes et les messages d'erreur.

    Ce club possède également un clavardage, on y trouve quelques perles entre deux sessions d'entraides.

  13. #13
    Membre chevronné Avatar de Ehonn
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2012
    Messages
    788
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2012
    Messages : 788
    Points : 2 160
    Points
    2 160
    Par défaut
    Citation Envoyé par Daïmanu Voir le message
    Mais il n'est pas mieux d'utiliser static_assert du coup, puisqu'il fait partie du langage ?
    Le i n'est pas forcément une constante de compilation (constexpr).

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

Discussions similaires

  1. winsock.h : undefined reference...
    Par abraxas dans le forum Dev-C++
    Réponses: 14
    Dernier message: 06/08/2012, 13h42
  2. Traitement d'un char* renvoyé par une DLL en C++
    Par LuluTchab dans le forum Langage
    Réponses: 4
    Dernier message: 22/03/2003, 21h48
  3. [VB6] [Syntaxe] Fonction renvoyant un tableau d'objets
    Par Troopers dans le forum VB 6 et antérieur
    Réponses: 2
    Dernier message: 18/10/2002, 15h33
  4. fonction renvoyant un tableau en argument
    Par Jones dans le forum Langage
    Réponses: 6
    Dernier message: 30/09/2002, 18h20
  5. [VB6]Passage par référence d'une prop. d'objet à une fct
    Par -gYs- dans le forum VB 6 et antérieur
    Réponses: 15
    Dernier message: 02/09/2002, 08h55

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