8

これは安全な回避策ですか? vector boolを使用したいのですが、C スタイルの配列を期待する古いコードへのポインターを渡す必要があります。

typedef std::basic_string<bool> vector_bool;

int main()
{
    vector_bool ab;
    ab.push_back(true);
    ab.push_back(true);
    ab.push_back(true);
    ab.push_back(false);
    bool *b = &ab[0];
    b[1] = false;
}

編集:他の解決策の提案に感謝しますが、上記の解決策について明確な回答が欲しいです。ありがとう。

4

3 に答える 3

17

std::basic_string<bool>それがインスタンス化されるためstd::char_traits<bool>、標準でそれを定義する必要があるかどうか、または定義されているなどの明示的な特殊化のみを使用して、プライマリchar_traitsテンプレートを未定義のままにしておくことができるかどうかはわかりませんchar_traits<char>char_traits<bool>特殊化がユーザー定義型に依存している場合にのみ標準テンプレートを特殊化できるため、独自の特殊化を提供することはできません。これboolは明らかにそうではありません。そうは言っても、stdlib にデフォルトのchar_traits定義があり、有用なことを行うために のメンバーを必要とする文字列操作を使用しようとしない場合は、うまくいく可能性がありますchar_traits

あるいは、これはハックですが、うまくいくかもしれません:

struct boolish { bool value; };
inline boolish make_boolish(bool b) { boolish bish = { b }; return bish; }

std::vector<boolish> b;
b.push_back( make_boolish(true) );
bool* ptr = &b.front().value;

boolishboolishは自明な型であるため、の配列がの配列と同じ表現を持っている限りbool(コンパイラを確認する必要があります。static_assertパディングがないことを確認するために a を使用しました)、それでうまくいくかもしれません。と は同じ配列の一部ではないため*ptr、おそらくエイリアシング規則に違反して*++ptrいますが、ポインタをインクリメントしても次のポインタは指されませんboolish::value。 、 [basic.compound]/3 は++ptr次を「指している」と言っているようですがbool)。

構文は C++11 で少し簡単になります。必要はありませんmake_boolish...

#include <vector>
#include <assert.h>

struct boolish { bool value; };

int main()
{
  std::vector<boolish> vec(10);
  vec.push_back( boolish{true} );
  bool* ptr = &vec.front().value;
  assert( ptr[10] == true );
  ptr[3] = true;
  assert( vec[3].value == true );

  static_assert( sizeof(boolish) == sizeof(bool), "" );
  boolish test[10];
  static_assert( sizeof(test) == (sizeof(bool)*10), "" );
}
于 2013-03-07T14:46:09.753 に答える
2

「ワーキング ドラフト C++、2012-11-02」より

21.1 一般 [strings.general]
1 この節では、配列以外の POD (3.9) 型のシーケンスを操作するためのコンポーネントについて説明します。

21.4.1 basic_string の一般要件 [string.require]
5 basic_string オブジェクト内の char のようなオブジェクトは、連続して格納されなければならない。つまり、任意の basic_string オブジェクト s について、同一性 &*(s.begin() + n) == &*s.begin() + n は、0 <= n < s.size となる n のすべての値に対して保持されます。 ().

しかし

6 basic_string シーケンスの要素を参照する参照、ポインター、および反復子は、その basic_string オブジェクトの次の使用によって無効化される場合があり ます

operator[]、at、front、back、begin、rbegin、end、rend を除く非 const メンバー関数の呼び出し。

したがって、生の配列を別の場所で使用している間は、これらの関数を呼び出さないように注意する限り安全です。

更新

文字特性と要件は、21.2 文字特性 [char.traits]および21.2.1 文字特性要件 [char.traits.require]で説明されています。さらに、typedef と特殊化は、それぞれ 21.2.2 特性 typedef [char.traits.typedefs]21.2.3 char_traits 特殊化 [char.traits.specializations]で説明されています。

これらの特性は、入出力ライブラリでも使用されます。eof()そのため、またはpos_typeやのような要件がありoff_type、 のコンテキストでは意味がありませんbasic_string

charchar16_tchar32_tおよびwchar_t. _

ただし、あなたの例ではgcc 4.7でそのまま使用できましたが、最小限のものを定義bool_traitsしました

struct bool_traits {
    typedef bool char_type;
    static void assign(char_type &r, char_type d);
    static char_type *copy(char_type *s, const char_type *p, std::size_t n);
    static char_type *move(char_type *s, const char_type *p, std::size_t n);
};

提供されたデフォルトの実装(gcc 4.7)を取り、それを次のように使用しました

std::basic_string<bool, bool_traits> ab;

お使いの環境では、機能する実装が既に提供されている場合があります。そうでない場合は、シンプルbool_traitsまたはテンプレートの特殊化をstd::char_traits<bool>自分で実装できます。

文字特性の完全なインターフェイスは、ワーキング ドラフト、PDF、またはcppreference.com - std::char_traitsで確認できます。

于 2013-03-07T16:41:19.183 に答える