ti-enxame.com

Por que o vetor <bool> :: reference não retorna a referência ao 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 );
}

A compilação do exemplo acima produz o próximo erro:

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&)

Eu compilei usando g ++ (versão 4.6.1) assim:

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

A questão é por que isso acontece? É vector<bool>::reference não bool&? Ou é um bug do compilador?
Ou estou tentando algo estúpido? :)

57
BЈовић

O vetor é especializado em bool .

É considerado um erro do std. Usar vector<char> em vez de:

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

Ocasionalmente, você pode precisar de referências a um bool contido dentro do vetor. Infelizmente, usando vector<char> só pode fornecer referências a caracteres. Se você realmente precisa de bool&, confira a biblioteca Boost Containers . Possui uma versão não especializada de vector<bool>.

58
Pubby

Suas expectativas são normais, mas o problema é que std::vector<bool> tem sido um tipo de experimento pelo comitê C++. Na verdade, é uma especialização de modelo que armazena os valores bool compactados na memória: um bit por valor.

E como você não pode ter uma referência a um pouco, o problema é seu.

49
rodrigo

std::vector< bool > empacota seu conteúdo para que cada valor booleano seja armazenado em um bit, oito bits em um byte. Isso é eficiente em termos de memória, mas computacionalmente intensivo, pois o processador deve executar aritmética para acessar o bit solicitado. E não funciona com semântica de referência ou ponteiro bool, pois os bits em um byte não têm endereços no modelo de objeto C++.

Você ainda pode declarar uma variável do tipo std::vector<bool>::reference e use-o como se fosse bool&. Isso permite que algoritmos genéricos sejam compatíveis.

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

No C++ 11, você pode contornar isso usando auto e o && especificador que seleciona automaticamente uma referência lvalue vinculada ao elemento vetorial ou uma referência rvalue vinculada a um temporário.

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> é um contêiner não conforme. Para otimizar o espaço, ele empacota bools e não pode fornecer referência.

Usar boost::dynamic_bitset em vez disso.

15
reder

Apenas meus 2 centavos:

std::vector<bool>::reference é um typedef para struct _Bit_reference que é definido como

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); }
  };

Mudando a função assim, funciona (bem, compila pelo menos, não testou):

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: Alterei a condição de (v1! = V2), o que não era uma boa ideia, para (v1! = B).

5
jrok

Faça uma estrutura com um bool e faça o vector<> Usando esse tipo de estrutura.

Tentar:

vector<struct sb> Onde sb é struct {boolean b];

então você pode dizer

Push_back({true})

faz

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

1
Todd