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

質問編集履歴

4

補足

2016/05/14 05:15

投稿

Chironian
Chironian

スコア23274

title CHANGED
File without changes
body CHANGED
@@ -308,4 +308,9 @@
308
308
 
309
309
  return 0;
310
310
  }
311
- ```
311
+ ```
312
+
313
+ 【補足】
314
+ `gContainerList`への値設定時、初期化リストを使おうとしたのでずか、ContainerHolderのコピー・コンストラクタが呼び出され、unique_ptrを使っているので暗黙的にdeleteされており、コンパイル・エラーでした。
315
+ push_backやemplace_backではムーブだけでよいので、原因はよく分かりませんでした。
316
+ もし、分かる方がいらっしゃいましたら、何故初期化リストではコピー・コンストラクタが必要になるのかご教授頂けると幸いです。

3

自作

2016/05/14 05:15

投稿

Chironian
Chironian

スコア23274

title CHANGED
File without changes
body CHANGED
@@ -52,4 +52,260 @@
52
52
  たぶん、イテレータにboost:anyテクニックを応用すれば可能と思いますが、コピー時にnewすることになります。イテレータはコピー負荷が軽いことが前提な型っぽい(I/Fの多くが参照渡しではなく値渡し)ので、これは避けたいです。
53
53
 
54
54
  以前、[こちらで質問](https://teratail.com/questions/28543)し、その過程で思いついたものの改造版を[Qiitaへ投稿](http://qiita.com/Chironian/items/19575744d4e5ea53c648)しました。
55
- そのRangeクラス内にboost::anyテクニックを使って、異なるコンテナ用イテレータを保持することで対応できそうな気がしているのですが、その前に何か良いアイデアがあればと思い、質問させて頂いています。
55
+ そのRangeクラス内にboost::anyテクニックを使って、異なるコンテナ用イテレータを保持することで対応できそうな気がしているのですが、その前に何か良いアイデアがあればと思い、質問させて頂いています。
56
+
57
+ ###自作してみました
58
+ yohhoyさんに教えていただいたboostの実装を参考にしつつ、自作してみました。
59
+ イテレータではなく範囲ベースfor専用のレンジをboost:any的に保持してます。
60
+ 範囲ベースfor専用のレンジはQiitaへ投稿した[range-based forをより使いやすくする](http://qiita.com/Chironian/items/19575744d4e5ea53c648)を改造しました。
61
+
62
+ 後、下記ソースではContainerHolderもboost::anyのようにしてますが、こちらは勿体無い気がしてます。コンテナへの参照をunique_ptr<>で保持してます。わざわざヒープ領域に「参照変数領域」を確保していることになるので、なんか違う気がするのですが、良い方法を思いつきませんでした。
63
+
64
+ poly_range.h
65
+ ```C++
66
+ #ifndef POLY_RANGE_H
67
+ #define POLY_RANGE_H
68
+
69
+ #include <memory>
70
+
71
+ //----------------------------------------------------------------------------
72
+ // 範囲ベースforへ渡すリファレンサー(RBForReferencerの特化)
73
+ //----------------------------------------------------------------------------
74
+
75
+ template<class tPolyRangeBase, class tElementBase>
76
+ class PolyReferencer
77
+ {
78
+ tPolyRangeBase& mPolyRange;
79
+ public:
80
+ PolyReferencer(tPolyRangeBase& iPolyRange) : mPolyRange(iPolyRange)
81
+ { }
82
+
83
+ tElementBase& operator*()
84
+ {
85
+ return mPolyRange.mHolder->front();
86
+ }
87
+ tElementBase const& operator*() const
88
+ {
89
+ return mPolyRange.mHolder->front();
90
+ }
91
+ void operator++()
92
+ {
93
+ mPolyRange.mHolder->drop_front();
94
+ }
95
+ bool operator!=(PolyReferencer const& iRhs) const
96
+ {
97
+ if (!mPolyRange.mHolder.get())
98
+ return false;
99
+ return !mPolyRange.mHolder->empty();
100
+ }
101
+ };
102
+
103
+ //----------------------------------------------------------------------------
104
+ // 枚挙用Range
105
+ //----------------------------------------------------------------------------
106
+
107
+ template<class tElementBase>
108
+ class PolyRange
109
+ {
110
+
111
+ // ---<<< 基底クラス >>>---
112
+
113
+ struct HolderBase
114
+ {
115
+ virtual tElementBase & front() = 0;
116
+ virtual tElementBase const& front() const = 0;
117
+ virtual void drop_front() = 0;
118
+ virtual bool empty() const = 0;
119
+
120
+ // これがないとmsvc 2015の「反復子のデバッグのサポート」用の
121
+ // イテレータのデストラクタが呼ばれないため、異常動作する。
122
+ virtual ~HolderBase() { }
123
+ };
124
+
125
+ // ---<<< 実クラス >>>---
126
+
127
+ template<typename tIterator>
128
+ struct Holder : public HolderBase
129
+ {
130
+ tIterator mBegin;
131
+ tIterator mEnd;
132
+
133
+ Holder(tIterator&& iBegin, tIterator&& iEnd) :
134
+ mBegin(std::forward<tIterator>(iBegin)),
135
+ mEnd (std::forward<tIterator>(iEnd))
136
+ { }
137
+ ~Holder() = default;
138
+
139
+ tElementBase& front()
140
+ {
141
+ return *mBegin;
142
+ }
143
+ tElementBase const& front() const
144
+ {
145
+ return *mBegin;
146
+ }
147
+ void drop_front()
148
+ {
149
+ ++mBegin;
150
+ }
151
+ bool empty() const
152
+ {
153
+ return mBegin == mEnd;
154
+ }
155
+ };
156
+
157
+ // ---<<< 各種設定 >>>---
158
+
159
+ template<class, class> friend class PolyReferencer;
160
+ typedef PolyReferencer<PolyRange, tElementBase> PolyReferencer;
161
+
162
+ // ---<<< 記録領域 >>>---
163
+
164
+ std::unique_ptr<HolderBase> mHolder;
165
+
166
+ // ---<<< コンストラクタ >>>---
167
+
168
+ public:
169
+ PolyRange() { }
170
+
171
+ template<typename tIterator>
172
+ PolyRange(tIterator&& iBegin, tIterator&& iEnd) :
173
+ mHolder
174
+ (
175
+ new Holder<tIterator>
176
+ (
177
+ std::forward<tIterator>(iBegin),
178
+ std::forward<tIterator>(iEnd)
179
+ )
180
+ )
181
+ { }
182
+
183
+ PolyReferencer begin() {return PolyReferencer(*this);}
184
+ PolyReferencer end() {return PolyReferencer(*this);}
185
+ };
186
+
187
+ //----------------------------------------------------------------------------
188
+ // コンテナのホルダ
189
+ // 保持しているコンテナの範囲ベースfor専用Rangeを獲得する機能を持つ
190
+ //----------------------------------------------------------------------------
191
+
192
+ template<class tElementBase>
193
+ class ContainerHolder
194
+ {
195
+
196
+ // ---<<< 基底クラス >>>---
197
+
198
+ struct HolderBase
199
+ {
200
+ virtual ~HolderBase() { }
201
+ virtual PolyRange<tElementBase> getRange() = 0;
202
+ };
203
+
204
+ // ---<<< 実クラス >>>---
205
+
206
+ template<class tContainer>
207
+ struct Holder : public HolderBase
208
+ {
209
+ tContainer& mContainer;
210
+
211
+ Holder(tContainer& iContainer) : mContainer(iContainer)
212
+ { }
213
+ ~Holder() = default;
214
+
215
+ PolyRange<tElementBase> getRange()
216
+ {
217
+ return PolyRange<tElementBase>(std::begin(mContainer), std::end(mContainer));
218
+ }
219
+ };
220
+
221
+ // ---<<< 記録領域 >>>---
222
+
223
+ std::unique_ptr<HolderBase> mHolder;
224
+
225
+ // ---<<< コンストラクタ >>>---
226
+
227
+ public:
228
+ template<typename tContainer>
229
+ ContainerHolder(tContainer& iContainer) :
230
+ mHolder(new Holder<tContainer>(iContainer))
231
+ { }
232
+
233
+ PolyRange<tElementBase> getRange()
234
+ {
235
+ return mHolder->getRange();
236
+ }
237
+ };
238
+
239
+ #endif // POLY_RANGE_H
240
+ ```
241
+
242
+ 以下、サンプル・ソースです。
243
+ main.cpp
244
+ ```C++
245
+ #include <iostream>
246
+ #include <vector>
247
+ #include <string>
248
+ #include "poly_range.h"
249
+
250
+ // 要素の型
251
+ struct ElementBase
252
+ {
253
+ virtual ~ElementBase() { }
254
+ virtual char const* getName() = 0;
255
+ };
256
+
257
+ struct Foo : public ElementBase
258
+ {
259
+ std::string const mName;
260
+ char const* getName()
261
+ {
262
+ return mName.c_str();
263
+ }
264
+
265
+ Foo(std::string const& iName) : mName(iName) { }
266
+ };
267
+
268
+ struct Bar : public ElementBase
269
+ {
270
+ char const* mName;
271
+ char const* getName()
272
+ {
273
+ return mName;
274
+ }
275
+
276
+ Bar(char const* iName) : mName(iName) { }
277
+ };
278
+
279
+ // コンテナ
280
+ Foo gFooArray[]={ {"Foo0"}, {"Foo1"}, {"Foo2"} };
281
+ std::vector<Bar> gBarVector={ "Bar0", "Bar1", "Bar2" };
282
+
283
+ // コンテナのリスト
284
+ typedef ContainerHolder<ElementBase> Container;
285
+ std::vector<Container> gContainerList;
286
+
287
+ int main()
288
+ {
289
+ std::size_t aFooArrayIndex=gContainerList.size();
290
+ gContainerList.emplace_back(Container(gFooArray));
291
+
292
+ std::size_t aBarVectorIndex=gContainerList.size();
293
+ gContainerList.emplace_back(Container(gBarVector));
294
+
295
+ std::cout << "--- FooArray ---\n";
296
+ for (auto&& element : gContainerList[aFooArrayIndex].getRange())
297
+ {
298
+ std::cout << element.getName() << "\n";
299
+ }
300
+ std::cout << "\n";
301
+
302
+ std::cout << "--- BarVector ---\n";
303
+ for (auto&& element : gContainerList[aBarVectorIndex].getRange())
304
+ {
305
+ std::cout << element.getName() << "\n";
306
+ }
307
+ std::cout << "\n";
308
+
309
+ return 0;
310
+ }
311
+ ```

2

不足追加

2016/05/14 05:00

投稿

Chironian
Chironian

スコア23274

title CHANGED
File without changes
body CHANGED
@@ -5,16 +5,32 @@
5
5
  そのようなクラスをご存知の方、もしくは、簡単な方法をご存知の方がいましたら、是非、ご教授頂けないでしょうか?
6
6
 
7
7
  #####詳細
8
- 例えば、下記のようなコンテナが2つあるとします。
8
+ 例えば、下記のようなコンテナaFooArray[]とstd::vector<Bar>があるとします。
9
9
  ```C++
10
- class Foo
10
+ struct ElementBase
11
11
  {
12
+ virutal ~ElementBase() { }
13
+ virtual char const* getName() = 0;
14
+ };
15
+
16
+ struct Foo : public ElementBase
17
+ {
18
+ std::string const mName;
19
+ char const* getName()
20
+ {
21
+ return mName.c_str();
22
+ }
12
23
  :
13
24
  };
14
25
  Foo aFooArray[]={ ... };
15
26
 
16
- class Bar
27
+ struct Bar : public ElementBase
17
28
  {
29
+ char const* mName;
30
+ char const* getName()
31
+ {
32
+ return mName;
33
+ }
18
34
  :
19
35
  };
20
36
  std::vector<Bar> aBarVector={ ... };
@@ -29,6 +45,7 @@
29
45
  ```C++
30
46
  for (auto&& element : aContainerList[index].getRange())
31
47
  {
48
+ std::cout << element.getName() << "\n";
32
49
  }
33
50
  ```
34
51
 

1

表現修正とミス修正

2016/05/08 08:43

投稿

Chironian
Chironian

スコア23274

title CHANGED
File without changes
body CHANGED
@@ -1,20 +1,25 @@
1
- 生配列やvector等の要素を枚挙することは非常に多いと思います。
1
+ 生配列やvector等の要素を枚挙することは多いと思います。
2
- して、異なる型のコンテナの要素をポリモーフィズム的に枚挙したいのです。
2
+ の延長線上で、異なる型のコンテナの要素をポリモーフィズム的に枚挙したいのですが、最近のC++なら簡単と思っていたら、意外に難しいです
3
- 最近のC++なら簡単かと思っていたら、意外に難しいです。
3
+
4
4
  しかし、実は私がまだ把握できていない標準ライブラリやboost等にそのような機能をサポートしたクラスがありそうな気もしています。
5
-
6
5
  そのようなクラスをご存知の方、もしくは、簡単な方法をご存知の方がいましたら、是非、ご教授頂けないでしょうか?
7
6
 
8
7
  #####詳細
9
8
  例えば、下記のようなコンテナが2つあるとします。
10
9
  ```C++
11
- class Foo;
10
+ class Foo
11
+ {
12
+ :
13
+ };
12
14
  Foo aFooArray[]={ ... };
13
15
 
14
- class Bar;
16
+ class Bar
17
+ {
18
+ :
19
+ };
15
20
  std::vector<Bar> aBarVector={ ... };
16
21
  ```
17
- [boost:Any](http://cpplover.blogspot.jp/2007/02/inside-boostany.html)的なテクニックでそれぞれへのポインタを管理用コンテナに入れてます。
22
+ [boost:any](http://cpplover.blogspot.jp/2007/02/inside-boostany.html)的なテクニックでそれぞれへのポインタを管理用コンテナに入れてます。
18
23
  イメージは下記です。(実際にビルドしてないので雰囲気だけ。)
19
24
  ```C++
20
25
  std::vector<any> aContainerList={any(aFooArray), any(aBarVector)};
@@ -22,7 +27,7 @@
22
27
 
23
28
  そして、下記のようなイメージで枚挙処理を行いたいのです。
24
29
  ```C++
25
- for (auto&& : aContainerList[index].getRange())
30
+ for (auto&& element : aContainerList[index].getRange())
26
31
  {
27
32
  }
28
33
  ```