2011-12-06 7 views
46
#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); 
} 

コンパイルは上記の次のエラーを生成します。<bool> :: referenceがboolへの参照を返さないのはなぜですか?例の

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

私はこのように、G ++(バージョン4.6.1)を使用してコンパイル:これはなぜ起こるか疑問がある

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

vector<bool>::referencebool&ではありませんか?それともコンパイラのバグですか?
または、私は何か愚かな試みですか? :)

+12

残念ながら、その名前にもかかわらず、 'std :: vector 'は 'bool'の' vector'ではありません。 –

+1

回避策として、 'std :: unique_ptr (new bool [3])' ... –

+2

Herb Sutterの[コンテナはコンテナではありませんか?](http://www.gotw.ca/publications /mill09.htm)はちょうどこの問題です。 – legends2k

答えて

49

Vector is specialized for bool

stdの間違いとみなされます。代わりにvector<char>を使用してください:

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

時にはあなたは、ベクター内に含まれるブール値への参照が必要な場合があります。残念ながら、vector<char>を使用すると、charへの参照のみを与えることができます。 bool&が本当に必要な場合は、Boost Containers libraryをご覧ください。それはvector<bool>の未特定バージョンを持っています。

+3

新しい回避策とエイリアシングのための新しい 'using'構文の素晴らしいデモです。 –

+5

+1のスマートな使い方については、「使用しています」(意図していない)。 – Nawaz

+0

@Nawaz私は、いたずらが意図されたことを神に誓う。 –

15

std::vector<bool>は不適合コンテナです。スペースを最適化するために、boolをパックし、参照を提供することはできません。

代わりにboost::dynamic_bitsetを使用してください。

+0

参照を取得するには、operator [](結果はdynamic_bitset :: reference)を使用する必要があります。しかし、イテレータはありません。 'dynamic_bitset'がどのように異なっているか、あるいはそれ以上に優れているかどうかは言及していないため、 – reder

+2

-1です。もちろん、 'bool 'も返すことはできません。 – Potatoswatter

44

あなたの期待は普通ですが、問題はstd::vector<bool>がC++コミットによる実験の一種であるということです。これは、実際にテンプレートの特殊化であり、メモリに緊密にパックされたブール値を格納します。値ごとに1ビットです。

ビットへの参照ができないため、問題があります。

+7

+1。 std :: vector は、std :: vectorによって提供される機能のサブセットのみをサポートしています。作業ベクトルを取得するには、boolを別の型(char)に置き換える必要があるので、醜いです。 – josefx

+1

ほとんどの実験(すべてではないにしても)の委員が後悔しました! – curiousguy

5

ちょうど私の2セント:

std::vector<bool>::referenceは、このような機能を変更する

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

として定義されてstruct _Bit_referenceのtypedefである、それは動作します(まあ、少なくともコンパイル、テストしていません) :

template< typename T > 
void callIfToggled(bool v1, std::vector<bool>::reference v2, T & t) 
{ 
    bool b = v2; 
    if (v1 != b) 
    { 
     v2 = v1; 
     t.foo(); 
    } 
} 

編集:私は(!V1 = B)に、良いアイデアではなかった、(!V1 = V2)から状態を変更しました。

+1

これは動作しますが、これはg ++の拡張ですか? –

+1

これは拡張ではなく、GCCがベクトルの特殊化を実装する方法です。私はこれについてスタンダードが何を言っているのか分かりません。 lib/gcc/mingw32/4.6.1/include/C++/bitsのstd_bvector.hを自分で見ることができます。 (あなたのディレクトリツリーは異なるかもしれませんが、多分似ているかもしれません) – jrok

+0

確かに、この1つの特定のケースでは、 'ベクトル'がひどい誤称である理由をさらに説明します。他の_actual_コンテナで動作するコード状況。それでも、ここで使用可能な回避策は 'template void callIfToggled(B && v1、B && v2、T && t)'を使用し、 'v2'から変換演算子に依存することです参照を転送することに感謝する理由。名前の間違った選択を許していない、しかし! –

13

std::vector<bool>は、それぞれのブール値が1ビット、すなわち8ビットから1バイトに格納されるようにその内容をパックする。これは、プロセッサが要求されたビットにアクセスするために算術演算を実行しなければならないので、メモリ効率は高いが計算集約型である。バイト内のビットはC++オブジェクトモデルのアドレスを持たないため、bool参照またはポインタのセマンティクスでは機能しません。

タイプstd::vector<bool>::referenceの変数を宣言して、そのままbool&のように使用できます。これにより、ジェネリックアルゴリズムが互換性を持つようになります。C++ 11では

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

、あなたはautoと、自動的にベクトル要素または一時的に結合された右辺値参照にバインドされた左辺値参照を選択&&指定子を使用してこの問題を回避することができます。

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

良い答え、とりわけ '&&'の言及は、プロキシタイプ/イテレータを有用にするためにジェネリックコードにとって重要です。もちろん、ループでも同じように機能します: 'for(auto && it:bizarreContainer)' –

1

それでboolと構造を作成し、その構造体のタイプを使用してvector<>を作ります。

試してみてください。sbstruct {boolean b];

である、あなたが

push_back({true})

typedef struct sbool {bool b;} boolstruct;、その後vector<boolstruct> bs;

を行うと言うことができ

関連する問題