9

私は次の問題にたプロキシイテレータ/参照型を持つコンテナを実装しています.std::vector<bool>std::vector<bool>std::vector<bool>

#include <vector>
#include <type_traits>
int main() {
  using namespace std;
  vector<bool> vec = {true, false, true, false};
  auto value = vec[2];  // expect: "vector<bool>::value_type"
  const auto& reference = vec[2]; // expect: "vector<bool>::const_reference"

  static_assert(is_same<decltype(value), vector<bool>::value_type>::value, 
                "fails: type is vector<bool>::reference!");
  static_assert(is_same<decltype(reference), 
                        vector<bool>::const_reference>::value,
                "fails: type is const vector<bool>::reference&!"); 

  /// Consequence:
  auto other_value = value; 
  other_value = false; 
  assert(vec[2] == true && "fails: assignment modified the vector");
  • 両方の静的アサートがパスするようにプロキシ タイプを実装する方法はありますか?

  • このようなコンテナを実装する際に、この問題に対処する方法に関するガイドラインはありますか?

auto/ auto&/ auto&&/への変換演算子を使用することconst auto...でしょうか。

編集:より明確にするために例を作り直しました。以下のコメントについて@LucDantonに感謝します。

4

2 に答える 2

4

プロキシ とautoはうまく相互作用しません。これautoは、隠されているはずの型に関する情報が明らかになるためです。

スタイルのものに興味があるというリクエストがいくつかありましたoperator auto(基本的に、「私をタイプとして推測するときは、代わりにこのタイプを使用してください」)が、公式の提案にはなりませんでした。

もう 1 つの問題は、プロキシを使用するの唯一のインスタンス化であるvector<bool>ため、予期しないことです。非推奨にすることを要求する他の予備的な提案があり、最終的には特別目的のクラスを代わりに導入して、非特別なものに戻す必要があります。vectorvector<bool>bitvector

于 2013-11-22T12:26:06.090 に答える
3

よく知られvector<bool>ているように、プライマリ テンプレートと比較して非汎用のインターフェイスvector<T>を備えています。

関連する違いは、ネストされた型referenceconst_referenceが一般的なケースではtypedefforT&とであり、プロキシ クラス値の型が であることです。T const& reference boolvector<bool>

ベクトル要素にアクセスするときは、ベクトル オブジェクトの constness によってreference、またはconst_referenceが返されるかどうかが決まることを覚えておくことも重要operator[]です。さらに、auto参照修飾子を削除しますdecltypeが、それらは保持します。

/ の非 const / const ベクトルを見て、 、 and を使用してみましょうbool(プレーンはintプロキシのライブタイムの問題につながります)。次の動作が得られます。autodecltype(auto)auto const&auto&

#include <vector>
#include <type_traits>
#include <typeinfo>
#include <iostream>
#include <ios>

int main() {
  using namespace std;

  vector<bool> vb = { true, false, true, false };
  vector<int > vi = {    1,     0,    1,     0 };

  auto vb2 = vb[2];             // vector<bool>::reference != bool
  auto vi2 = vi[2];             // int
  decltype(auto) rvb2 = vb[2];  // vector<bool>::reference
  decltype(auto) rvi2 = vi[2];  // int&
  auto const& crvb2 = vb[2];    // vector<bool>::reference const& != bool const&
  auto const& crvi2 = vi[2];    // int const&

  auto ovb2 = vb2;
  ovb2 = false;                 // OOPS ovb2 has reference semantics
  cout << boolalpha << (vb[2] == true) << "\n";

  auto ovi2 = vi2;
  ovi2 = 0;                     // OK, ovi2 has value semantics
  cout << boolalpha << (vi[2] == 1) << "\n";

  static_assert(is_convertible<decltype(vb2),   vector<bool>::value_type>::value, "");  
  static_assert(is_same       <decltype(vi2),   vector<int >::value_type>::value, "");
  static_assert(is_same       <decltype(rvb2),  vector<bool>::reference>::value, "");  
  static_assert(is_same       <decltype(rvi2),  vector<int >::reference>::value, "");
  static_assert(is_convertible<decltype(crvb2), vector<bool>::const_reference>::value, "");  
  static_assert(is_same       <decltype(crvi2), vector<int >::const_reference>::value, "");

  vector<bool> const cvb = { true, false, true, false };
  vector<int > const cvi = {    1,     0,    1,     0 };   

  auto cvb2 = cvb[2];            // vector<bool>::const_reference == bool
  auto cvi2 = cvi[2];            // int
  decltype(auto) rcvb2 = cvb[2]; // vector<bool>::const_reference == bool
  decltype(auto) rcvi2 = cvi[2]; // int const&
  auto const& crcvb2 = cvb[2];   // vector<bool>::reference const& != bool const&
  auto const& crcvi2 = cvi[2];   // int const&

  static_assert(is_same       <decltype(cvb2),   vector<bool>::value_type>::value, "");  
  static_assert(is_same       <decltype(cvi2),   vector<int >::value_type>::value, "");
  static_assert(is_same       <decltype(rcvb2),  vector<bool>::const_reference>::value, "");  
  static_assert(is_same       <decltype(rcvi2),  vector<int >::const_reference>::value, "");
  static_assert(is_convertible<decltype(crcvb2), vector<bool>::const_reference>::value, "");  
  static_assert(is_same       <decltype(crcvi2), vector<int >::const_reference>::value, "");

  auto ocvb2 = cvb2;
  ocvb2 = false;                 // OK, ocvb2 has value semantics
  cout << boolalpha << (cvb[2] == true) << "\n";

  auto ocvi2 = cvi2;
  ocvi2 = 0;                     // OK, ocvi2 has value semantics
  cout << boolalpha << (cvi[2] == 1) << "\n";  
}

実際の例

非 constの場合、 onをvector<bool>使用すると、値のセマンティクスを持たない参照プロキシが得られることに注意してください。a を使用すると、それを回避できます。これを他の方法で解決する方法がわかりません。autooperator[]const vector<bool>

auto const&動作的に同等ですが、 の中にis_convertibleではなく があります。私はこれができる最善の方法だと思います。is_samestatic_assert

プロキシ コンテナーでの一般的な反復と STL アルゴリズムの場合、状況はそれほど暗くないことに注意してください。これに関する Hinnant のコラムを参照してください。

于 2013-11-22T09:57:22.620 に答える