teratail header banner
teratail header banner
質問するログイン新規登録

質問編集履歴

1

その後を追加

2016/03/01 15:12

投稿

Chironian
Chironian

スコア23274

title CHANGED
File without changes
body CHANGED
@@ -13,4 +13,184 @@
13
13
  ---
14
14
  【閑話休題】
15
15
  なぜに範囲ベースforはiteratorを返さないのでしょう?
16
- [for-range-declaration = *__begin;](http://cpplover.blogspot.jp/2009/08/n2930-range-based-for-loop.html)じゃなくて、`for-range-declaration = __begin;`なら良かったのに。
16
+ [for-range-declaration = *__begin;](http://cpplover.blogspot.jp/2009/08/n2930-range-based-for-loop.html)じゃなくて、`for-range-declaration = __begin;`なら良かったのに。
17
+
18
+ ---
19
+ 【その後】
20
+ その後、調べていて、ランダム・アクセス・イレテータでないコンテナの場合、std:distance()はリストを追跡するらしいことが分かりました。ということは同様にoperator[]も追跡する筈ですね。(何を今更なのですが。)
21
+ 今はvectorで範囲ベースforを使ってますが一部はforward_listへ変更します。これを見越すと、インデックスを使うためにはイテレータ型のfor文へ変更しインデックスも追加する必要があります。for文がごちゃごちゃになり、範囲ベースforとの落差に悶え死にそうでした。しかも、autoの型が変わってしまうし...
22
+
23
+ 個人的にこれらが許せないので、yumetodoさんのリンク先の記事からヒントを得て、ツールを作りました。
24
+ 考え方は、自作の隠しイテレータをコンパイラへ返して、それがインクリメントされた時にインデックスも一緒にインクリメントするイメージです。
25
+ ですので、listでも使えますし、listのイテレータをdistanceした時のような追跡処理も発生しません。そして、autoで推論される型は同じコンテナの要素のままですので、範囲ベースforブロック内の変更も不要です。
26
+
27
+ ```C++
28
+ #include <iterator>
29
+
30
+ // ***************************************************************************
31
+ // 範囲ベースforにインデックス機能を追加する
32
+ // ***************************************************************************
33
+
34
+ namespace staff_only
35
+ {
36
+
37
+ //----------------------------------------------------------------------------
38
+ // 隠しイテレータ・クラス
39
+ //----------------------------------------------------------------------------
40
+
41
+ template<typename tValueType, typename tParentIterator>
42
+ class Iterator
43
+ {
44
+ tParentIterator mParentIterator;
45
+ std::size_t& mIndexReference;
46
+ public:
47
+ explicit Iterator(tParentIterator iIterator, std::size_t& iIndexReference) :
48
+ mParentIterator(iIterator),
49
+ mIndexReference(iIndexReference)
50
+ { }
51
+
52
+ tValueType& operator*() {return *mParentIterator;}
53
+ tParentIterator& operator++()
54
+ {
55
+ ++mParentIterator;
56
+ ++mIndexReference;
57
+ return mParentIterator;
58
+ }
59
+ bool operator==(Iterator const& rhs) {return mParentIterator==rhs.mParentIterator;}
60
+ bool operator!=(Iterator const& rhs) {return mParentIterator!=rhs.mParentIterator;}
61
+ };
62
+
63
+ //----------------------------------------------------------------------------
64
+ // コンテナ
65
+ //----------------------------------------------------------------------------
66
+
67
+ template<class tContainer>
68
+ class Indexer
69
+ {
70
+ typedef typename tContainer::value_type ValueType;
71
+ typedef typename tContainer::iterator ParentIterator;
72
+ typedef Iterator<ValueType, ParentIterator> InnerIterator;
73
+
74
+ // Indexer実体
75
+ tContainer& mContainer;
76
+ std::size_t& mIndexReference;
77
+ public:
78
+ explicit Indexer(tContainer& iContainer, std::size_t& iIndexReference) :
79
+ mContainer(iContainer),
80
+ mIndexReference(iIndexReference)
81
+ {
82
+ mIndexReference=0;
83
+ }
84
+ InnerIterator begin()
85
+ {
86
+ return InnerIterator(mContainer.begin(), mIndexReference);
87
+ }
88
+ InnerIterator const end() const
89
+ {
90
+ return InnerIterator(mContainer.end(), mIndexReference);
91
+ }
92
+ };
93
+
94
+ //----------------------------------------------------------------------------
95
+ // 生配列
96
+ //----------------------------------------------------------------------------
97
+
98
+ template<class tValueType, size_t tDim>
99
+ class Indexer<tValueType[tDim]>
100
+ {
101
+ typedef tValueType* ParentIterator;
102
+ typedef Iterator<tValueType, ParentIterator> InnerIterator;
103
+
104
+ // Indexer実体
105
+ typedef tValueType Container[tDim];
106
+ Container& mContainer;
107
+ std::size_t& mIndexReference;
108
+ public:
109
+ explicit Indexer(Container& iContainer, std::size_t& iIndexReference) :
110
+ mContainer(iContainer),
111
+ mIndexReference(iIndexReference)
112
+ {
113
+ mIndexReference=0;
114
+ }
115
+ InnerIterator begin()
116
+ {
117
+ return InnerIterator(&mContainer[0], mIndexReference);
118
+ }
119
+ InnerIterator const end() const
120
+ {
121
+ return InnerIterator(&mContainer[tDim], mIndexReference);
122
+ }
123
+ };
124
+ } // namespace staff_only
125
+
126
+ //----------------------------------------------------------------------------
127
+ // API
128
+ //----------------------------------------------------------------------------
129
+
130
+ template<class tContainer>
131
+ staff_only::Indexer<tContainer> getIndexer(tContainer& iContainer, std::size_t& iIndexReference)
132
+ {
133
+ return staff_only::Indexer<tContainer>(iContainer, iIndexReference);
134
+ }
135
+
136
+ // ***************************************************************************
137
+ // 使い方
138
+ // ***************************************************************************
139
+
140
+ #include <array>
141
+ #include <vector>
142
+ #include <forward_list>
143
+ #include <list>
144
+
145
+ #include <iostream>
146
+
147
+ int main()
148
+ {
149
+ struct TestClass
150
+ {
151
+ int x, y;
152
+ };
153
+ TestClass wRawArray[] = {{5,1}, {4,2}, {3,3}, {2,4}, {1,5}, {0,6}};
154
+ std::array<TestClass, 5> wArray ={{{4,2}, {3,3}, {2,4}, {1,5}, {0,6}}};
155
+ std::vector<TestClass> wVector = {{3,3}, {2,4}, {1,5}, {0,6}};
156
+ std::forward_list<TestClass> wForwardList= {{2,4}, {1,5}, {0,6}};
157
+ std::list<TestClass> wList = {{1,5}, {0,6}};
158
+
159
+ std::size_t wIndex;
160
+
161
+ std::cout << "raw-array\n";
162
+ for (auto& wData : getIndexer(wRawArray, wIndex)) {
163
+ std::cout << "[" << wIndex << "]=" << wData.x << ", " << wData.y << "\n";
164
+ }
165
+
166
+ std::cout << "\nstd::array\n";
167
+ for (auto& wData : getIndexer(wArray, wIndex)) {
168
+ std::cout << "[" << wIndex << "]=" << wData.x << ", " << wData.y << "\n";
169
+ }
170
+
171
+ std::cout << "\nstd::vector\n";
172
+ for (auto& wData : getIndexer(wVector, wIndex)) {
173
+ std::cout << "[" << wIndex << "]=" << wData.x << ", " << wData.y << "\n";
174
+ }
175
+
176
+ std::cout << "\nstd::forward_list\n";
177
+ for (auto& wData : getIndexer(wForwardList, wIndex)) {
178
+ std::cout << "[" << wIndex << "]=" << wData.x << ", " << wData.y << "\n";
179
+ }
180
+
181
+ std::cout << "\nstd::list\n";
182
+ for (auto& wData : getIndexer(wList, wIndex)) {
183
+ std::cout << "[" << wIndex << "]=" << wData.x << ", " << wData.y << "\n";
184
+ }
185
+
186
+ return 0;
187
+ }
188
+
189
+
190
+ ```
191
+
192
+ msvc2015とMinGW 5.2.0で動作確認してます。
193
+
194
+ 2点不満が残りました。orz
195
+ イテレータはこっそりインクリメントされているので、インデックスもこっそりインクリメントされます。範囲ベースforの仕様とも言えるのでこの点は許容することにしました。
196
+ インデックスのスコープがforの外側になってしまいます。内側にしたいのですが、範囲ベースforの構文に割り込めず諦め。