#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? :)
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>
.
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.
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
std::vector<bool>
est un conteneur non conforme. Pour optimiser l'espace, il contient bool
s et ne peut pas fournir de référence.
Utilisation boost::dynamic_bitset
à la place.
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).
Créez une structure contenant un bool
et créez le vector<>
En utilisant ce type de structure.
Essayer:
vector<struct sb>
Où sb
est struct {boolean b];
alors tu peux dire
Push_back({true})
faire
typedef struct sbool {bool b;} boolstruct;
Puis vector<boolstruct> bs;