Pourquoi vector<bool>::référence 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é à l'aide de g++ (version 4.6.1) comme ceci :
g++ -O3 -std=c++0x -Wall -Wextra -pedantic dk2.cpp
La question est de savoir pourquoi cela se produit? Est vector<bool>::reference
pas bool&
? Ou est-ce un bug du compilateur?
Ou, suis-je en train d'essayer quelque chose de stupide? 🙂
- Malheureusement, en dépit de son nom,
std::vector<bool>
n'est pas unvector
debool
. - Comme solution de contournement, vous pouvez utiliser
std::unique_ptr<bool[]>(new bool[3])
... - Herb Sutter est Quand Est un Conteneur, Pas un Conteneur? c'est juste à propos de ce problème.
- Howard Hinnant l'article de Sur vector<bool> dit que c'est une bonne optimisation, seulement le nom aurait été modifié pour ne plus désigner le plus de sens d'un conteneur standard.
Vous devez vous connecter pour publier un commentaire.
Vecteur est spécialisé pour le type bool.
Il est considéré comme une erreur de la std. Utilisation
vector<char>
à la place:Parfois vous pouvez avoir besoin de références pour un bool contenues dans le vecteur. Malheureusement, à l'aide de
vector<char>
ne peut que vous donner les références de caractères. Si vous avez vraiment besoinbool&
, découvrez la Stimuler les Conteneurs de la bibliothèque. Il dispose d'une non spécialisé à la version devector<bool>
.using
syntaxe pour créer un alias.using
(no pun intended).Vos attentes sont normales, mais le problème est que
std::vector<bool>
a été une sorte d'expérience par le C++ comité. Il est en fait un modèle de spécialisation qui stocke les valeurs bool serrés dans la mémoire: un bit de valeur.Et puisque vous ne pouvez pas avoir une référence pour un peu, il y a votre problème.
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 avecbool
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 si c'étaitbool&
. Cela permet à des algorithmes génériques pour être compatible.En C++11, vous pouvez contourner cela en utilisant
auto
et 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.&&
, ce qui est crucial pour le code générique de laisser les types de proxy/itérateurs être utile. Bien sûr, il fonctionne aussi bien dans les boucles:for (auto &&it: bizarreContainer)
std::vector<bool>
est un non-conforme conteneur. Pour optimiser l'espace, il emballebool
s et ne peut pas fournir de référence.Utilisation
boost::dynamic_bitset
à la place.dynamic_bitset
est différent ou mieux. Bien sûr, il ne peut pas retourner unbool &
soit.Juste mes 2 cents:
std::vector<bool>::reference
est un typedef pourstruct _Bit_reference
qui est définie commeLa modification de la fonction comme ceci, ça fonctionne (bien, compile au moins, ne l'ai pas testé):
EDIT: j'ai changé la condition de (v1 != v2), ce qui n'était pas une bonne idée, à (v1 != b).
vector<bool>
est un affreux abus de langage - qu'il devient extrêmement difficile, fastidieux, voire impossible à utiliser dans le code général des situations de travail pour les autres, réel conteneurs. Encore, je pense utilisable solution ici serait de l'utilisertemplate<typename B, typename T> void callIfToggled(B &&v1, B &&v2, T &&t)
et de s'appuyer sur l'opérateur de conversion dev2
- qui, j'imagine, est une autre raison d'être reconnaissants pour le transfert des références. N'est pas une excuse pour le mauvais choix de nom, si!Faire une structure avec un
bool
en elle, et de faire de lavector<>
utilisant ce type struct.Essayer:
vector<struct sb>
oùsb
eststruct {boolean b];
alors vous pouvez dire
push_back({true})
ne
typedef struct sbool {bool b;} boolstruct;
et puisvector<boolstruct> bs;
struct
outypedef
en C++