63 votes

Pourquoi vecteur <bool> :: reference ne renvoie pas reference to 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 génère 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? Est-ce que vector<bool>::reference n'est pas bool& ? Ou est-ce un bug du compilateur?
Ou est-ce que j'essaie quelque chose de stupide? :)

67voto

Pubby Points 29386

Vector est spécialisé pour bool .

C'est considéré comme une erreur de la std. Utilisez vector<char> place:

 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...>;
 

54voto

rodrigo Points 34500

Vos attentes sont normales, mais le problème est que std::vector<bool> a été une sorte d’expérience réalisée 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, voilà votre problème.

23voto

Potatoswatter Points 70305

std::vector< bool > packs de son contenu, de sorte que chaque valeur Booléenne est stocké dans un bit, huit bits d'un octet. C'est efficace de la mémoire, mais de calcul intensif, puisque le processeur doit effectuer l'arithmétique d'accéder à la demande de bits. Et il ne fonctionne pas avec bool de référence ou pointeur de la sémantique, puisque les bits dans un octet n'ont pas d'adresses dans le C++ modèle d'objet.

Vous pouvez toujours déclarer une variable de type std::vector<bool>::reference et l'utiliser comme s'il s'agissait bool&. Cela permet à des algorithmes génériques pour être compatible.

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 cela en utilisant auto et de la && spécificateur qui sélectionne automatiquement une lvalue de référence lié à l'élément du vecteur ou une référence rvalue lié à un emploi temporaire.

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

15voto

reder Points 664

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

Utilisez boost::dynamic_bitset place.

5voto

jrok Points 30472

Juste mes 2 centimes:

std::vector<bool>::reference est un typedef pour struct _Bit_reference 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 ainsi, ça marche (enfin, compile au moins, n’a pas été 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, en (v1! = B).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X