2015-03-05 1 views
0

Le code suivant ne compile pas| = sur std :: vecteur <bool>

#include <vector> 
int main() 
{ 
    std::vector<bool> enable(10); 
    enable[0] |= true; 
    return 0; 
} 

donnant l'erreur

no match for ‘operator|=’ (operand types are ‘std::vector<bool>::reference {aka std::_Bit_reference}’ and ‘bool’) 

Dans mon vrai code vie, j'ai un champ de bits avec des valeurs que je veux à |= avec le résultat d'une fonction.

Il existe un moyen facile d'exprimer la même idée, mais y a-t-il une bonne raison pour qu'un tel opérateur ne soit pas disponible?

+4

Vous pouvez toujours faire 'enable [0] = enable [0] | ... '. –

+0

Pourquoi ne pas utiliser un ['bitset'] (http://en.cppreference.com/w/cpp/utility/bitset) – Borgleader

+0

@Borgleader dans mon code réel la longueur est dynamique – Amxx

Répondre

3

La raison principale serait que std::vector<bool> est spécial, et sa spécification permet spécifiquement une mise en œuvre pour minimiser l'utilisation de la mémoire.

Pour les vecteurs d'autre chose que bool, le type de référence peut effectivement être une véritable référence (à savoir std::vector<int>::reference peut effectivement être un int &) - généralement directement référence à un élément du vecteur lui-même. Il est donc logique que le type de référence prenne en charge toutes les opérations que peut effectuer le type sous-jacent. Cela fonctionne car vector<int> gère efficacement un tableau contigu de int en interne. La même chose vaut pour tous les types autres que bool. Cependant, pour minimiser l'utilisation de la mémoire, un std::vector<bool> peut ne pas (en fait probablement ne fonctionnera pas) fonctionner en interne avec un tableau réel de bool. Au lieu de cela, il peut utiliser une structure de données empaquetée, telle qu'un tableau de unsigned char en interne, où chaque unsigned char est un bitfield contenant 8 bits. Donc un vector<bool> de longueur 800 gèrerait réellement un tableau de 100 char non signé, et la mémoire qu'il consomme serait 100 octets (en supposant qu'il n'y ait pas de surallocation). Si le vector<bool> contenait en fait un tableau de 800bool, son utilisation de la mémoire serait un minimum de 800 octets (puisque sizeof (bool) doit être au moins 1, par définition).

pour permettre une telle optimisation de la mémoire par les opérateurs de vector<bool>, le type de retour de vector<bool>::operator[] (à savoir std::vector<bool>::reference) ne peut pas être simplement un bool &. En interne, il contient probablement une référence au type sous-jacent (par exemple, un unsigned char) et des informations permettant de suivre le bit qu'il affecte réellement. Ceci rendrait tous les opérateurs op = (+=, -=, |=, etc.) des opérations quelque peu coûteuses (par exemple, un médiateur de bits) sur le type sous-jacent.

Les concepteurs de std::vector<bool> auraient alors dû faire un choix entre

  1. précise que std::vector<bool>::reference soutenir tous les op = et entendre les plaintes continuelles au sujet de l'inefficacité de l'exécution de programmeurs qui utilisent ces opérateurs

  2. Ne soutenez pas ces op = et les plaintes de terrain des programmeurs qui pensent que de telles choses sont correctes ("code propre", etc) même si elles seront inefficaces.

Il semble que les concepteurs de std::vector<bool> ont opté pour l'option 2. Une conséquence est que les seuls opérateurs d'affectation pris en charge par std::vector<bool>::reference sont le stock norme operator=() (avec opérandes soit de type reference, ou de type bool) pas de l'op =. L'avantage de ce choix est que les programmeurs obtiennent une erreur de compilation s'ils essaient de faire quelque chose qui est en fait un mauvais choix dans la pratique.

Après tout, bien que bool supporte tous les op = en les utilisant ne réalise pas beaucoup de toute façon. Par exemple, some_bool |= true a le même effet net que some_bool = true.

1

Pourquoi ne faites-vous pas ce qui suit?

enable[0] = enable[0] | true; 
+0

C'est ce que je suis en train de faire, mais je trouverais un opérateur | = plus propre ... (pas que j'adore ce genre d'opérateur, comme faire^^ = true »pour basculer un booléen) – Amxx

+0

Vous pourriez surcharger l'opérateur comme suggéré par David Schwartz, mais je pense que pour une opération aussi élémentaire, c'est assez bon. Ton appel. – erip

+0

Je ne pense pas non plus qu'il soit utile d'ajouter un opérateur (surtout s'il est mal écrit et contient des branches). Pourtant pour moi le point principal d'un opérateur comme '| =' est de ne pas avoir à la variable, réduire les risques d'un tipo – Amxx

1

Vous devriez être capable d'en fabriquer un vous-même assez facilement. Quelque chose comme:

std::vector<bool>::reference& operator |= (std::vector<bool>::reference& a, bool b) 
{ 
    if (b) 
     a = true; 
    return a; 
} 

Sinon, std::bitset est un bon ajustement.

0

Réponse courte et douce: std::vector<bool> doit être évitée. Utilisez vector<wchar> à la place. En fait, vous obtenez un conteneur dans lequel les booléens sont emballés en bits, ce qui donne un comportement différent de celui des autres vecteurs, du code lent et personne ne se soucie de la mémoire de toute façon. Je suppose que maintenant personne ne l'aime plus, mais en retournant l'horloge casserait trop de code ...