web-dev-qa-db-fra.com

Pourquoi le vecteur <bool> :: reference ne renvoie pas de référence à bool?

#include <vector>

struct A
{
    void foo(){}
};

template< typename T >
void callIfToggled( bool v1, bool &v2, T & t )
{
    if ( v1 != v2 )
    {
        v2 = v1;
        t.foo();
    }
}

int main()
{
    std::vector< bool > v= { false, true, false };

    const bool f = false;
    A a;

    callIfToggled( f, v[0], a );
    callIfToggled( f, v[1], a );
    callIfToggled( f, v[2], a );
}

La compilation de l'exemple ci-dessus produit l'erreur suivante:

dk2.cpp: In function 'int main()':
dk2.cpp:29:28: error: no matching function for call to 'callIfToggled(const bool&, std::vector<bool>::reference, A&)'
dk2.cpp:29:28: note: candidate is:
dk2.cpp:13:6: note: template<class T> void callIfToggled(bool, bool&, T&)

J'ai compilé en utilisant g ++ (version 4.6.1) comme ceci:

g++ -O3 -std=c++0x -Wall -Wextra -pedantic dk2.cpp

La question est pourquoi cela se produit-il? Est vector<bool>::reference ne pas bool&? Ou s'agit-il d'un bug de compilation?
Ou est-ce que j'essaye quelque chose de stupide? :)

57
BЈовић

Le vecteur est spécialisé pour bool .

Il est considéré comme une erreur de la std. Utilisation vector<char> au lieu:

template<typename t>
struct foo {
  using type = t;
};
template<>
struct foo<bool> {
  using type = char;
};

template<typename t, typename... p>
using fixed_vector = std::vector<typename foo<t>::type, p...>;

Parfois, vous pouvez avoir besoin de références à un booléen contenu dans le vecteur. Malheureusement, en utilisant vector<char> ne peut vous donner que des références aux caractères. Si vous avez vraiment besoin de bool&, consultez la bibliothèque Boost Containers . Il a une version non spécialisée de vector<bool>.

58
Pubby

Vos attentes sont normales, mais le problème est que std::vector<bool> a été une sorte d'expérience par le comité C++. Il s'agit en fait d'une spécialisation de modèle qui stocke les valeurs booléennes étroitement emballées en mémoire: un bit par valeur.

Et puisque vous ne pouvez pas avoir une référence à un peu, il y a votre problème.

49
rodrigo

std::vector< bool > compresse son contenu pour que chaque valeur booléenne soit stockée dans un bit, huit bits dans un octet. Ceci est économe en mémoire mais gourmand en calculs, car le processeur doit effectuer une arithmétique pour accéder au bit demandé. Et cela ne fonctionne pas avec la sémantique de référence ou de pointeur bool, car les bits d'un octet n'ont pas d'adresse dans le modèle d'objet C++.

Vous pouvez toujours déclarer une variable de type std::vector<bool>::reference et l'utiliser comme si c'était bool&. Cela permet aux algorithmes génériques d'être compatibles.

std::vector< bool > bitvec( 22 );
std::vector< bool >::reference third = bitvec[ 2 ];
third = true; // assign value to referenced bit

En C++ 11, vous pouvez contourner ce problème en utilisant auto et && spécificateur qui sélectionne automatiquement une référence lvalue liée à l'élément vecteur ou une référence rvalue liée à un élément temporaire.

std::vector< bool > bitvec( 22 );
auto &&third = bitvec[ 2 ]; // obtain a std::vector< bool >::reference
third = true; // assign value to referenced bit
15
Potatoswatter

std::vector<bool> est un conteneur non conforme. Pour optimiser l'espace, il contient bools et ne peut pas fournir de référence.

Utilisation boost::dynamic_bitset à la place.

15
reder

Juste mes 2 cents:

std::vector<bool>::reference est un typedef pour struct _Bit_reference qui est défini comme

typedef unsigned long _Bit_type;

struct _Bit_reference
  {
    _Bit_type * _M_p;
    _Bit_type _M_mask;

    // constructors, operators, etc...

    operator bool() const
    { return !!(*_M_p & _M_mask); }
  };

Changer la fonction comme ça, ça marche (enfin, compile au moins, pas testé):

template< typename T >
void callIfToggled( bool v1, std::vector<bool>::reference v2, T & t )
{
    bool b = v2;  
    if ( v1 != b )
    {
        v2 = v1;
        t.foo();
    }
}

EDIT: J'ai changé la condition de (v1! = V2), ce qui n'était pas une bonne idée, à (v1! = B).

5
jrok

Créez une structure contenant un bool et créez le vector<> En utilisant ce type de structure.

Essayer:

vector<struct sb>sb est struct {boolean b];

alors tu peux dire

Push_back({true})

faire

typedef struct sbool {bool b;} boolstruct; Puis vector<boolstruct> bs;

1
Todd