C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[7]: テンプレート変数からイテレータ変数の宣言


(過去ログ 53 を表示中)

[トピック内 21 記事 (1 - 20 表示)]  << 0 | 1 >>

■29827 / inTopicNo.1)  テンプレート変数からイテレータ変数の宣言
  
□投稿者/ 七篠 (13回)-(2008/12/15(Mon) 16:56:38)

分類:[C/C++] 

こんにちは。

宣言された変数から自分の型のイテレータ変数を宣言させることは可能でしょうか?
具体的にはこのような感じです。

list<int> foo;

for(foo.(::?)iterator i = foo.begin(); i != foo.end(); i++)
{

もちろん、このままでは上手くいかないので、list をテンプレートクラスで
ラップし、そのクラス内で

template<class T>
class List
{
 list<T> foo;

 typename typedef list<T>::iterator	Iterator;

このような記述をしたのですが

List<int>::Iterator

このように書かなければコンパイルが通らず、意味がありません。

解決案、代替案がある方、ご教授いただければ幸いです。

引用返信 編集キー/
■29835 / inTopicNo.2)  Re[1]: テンプレート変数からイテレータ変数の宣言
□投稿者/ aetos (43回)-(2008/12/15(Mon) 17:44:26)
No29827 (七篠 さん) に返信
> こんにちは。
>
> 宣言された変数から自分の型のイテレータ変数を宣言させることは可能でしょうか?
> 具体的にはこのような感じです。
>
> list<int> foo;
>
> for(foo.(::?)iterator i = foo.begin(); i != foo.end(); i++)
> {

C++0x の decltype が実現しようとしていることなんだろうな。
http://d.hatena.ne.jp/faith_and_brave/20081208/1228727575

というわけで、言語自体にそういう機能は、今はまだありません。
どこぞの変態ライブラリにあるかどうかは知りませんが。
引用返信 編集キー/
■29842 / inTopicNo.3)  Re[2]: テンプレート変数からイテレータ変数の宣言
□投稿者/ 774RR (259回)-(2008/12/15(Mon) 18:20:52)
変数名からの推論は簡単にできないので、俺なら変更箇所を1つにする意味では
typedef list<int> container_type; // ここを変更するだけでいい
container_type foo;
for (container_type::iterator it=foo.begin(); it!=foo.end(); ++i) { ... }
としておくかな
container_type::value_type とか、その辺いろいろ使えるようになるし。
引用返信 編集キー/
■29846 / inTopicNo.4)  Re[1]: テンプレート変数からイテレータ変数の宣言
□投稿者/ アキラ (134回)-(2008/12/15(Mon) 18:56:38)
アキラ さんの Web サイト
No29827 (七篠 さん) に返信

Boost.Typeof使えばできるんですけど

#include <vector>
#include <boost/typeof/typeof.hpp>

using namespace std;

int main()
{
    vector<int> v;
    BOOST_TYPEOF(v)::iterator it = v.begin();
}

Boost.TypeofはVCの場合、VCのバグを利用して実装されてるので
そのバグが修正されたら動かなくなるのでオススメはしません。

引用返信 編集キー/
■29852 / inTopicNo.5)  Re[2]: テンプレート変数からイテレータ変数の宣言
□投稿者/ uskz (1回)-(2008/12/15(Mon) 21:31:01)
> Boost.TypeofはVCの場合、VCのバグを利用して実装されてるので
> そのバグが修正されたら動かなくなるのでオススメはしません。

この辺のportability気になるならBOOST_TYPEOF_COMPLIANTを#defineしてemulation modeで書いとけば良いんじゃないですかね.新しい型作ったら自分で登録しないといけないですけれども.
引用返信 編集キー/
■29856 / inTopicNo.6)  Re[3]: テンプレート変数からイテレータ変数の宣言
□投稿者/ アキラ (135回)-(2008/12/15(Mon) 22:26:30)
アキラ さんの Web サイト
2008/12/16(Tue) 00:57:28 編集(投稿者)
No29852 (uskz さん) に返信
> この辺のportability気になるならBOOST_TYPEOF_COMPLIANTを#defineしてemulation modeで書いとけば良いんじゃないですかね.
> 新しい型作ったら自分で登録しないといけないですけれども.

おー、こんなのあったんですね。
こうかな、と。

#include <vector>

#define BOOST_TYPEOF_COMPLIANT // エミュレーションモードを使用
#include <boost/typeof/typeof.hpp>

// BOOST_TYPEOFで使用できる型を登録
#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
BOOST_TYPEOF_REGISTER_TYPE(std::vector<int>);

int main()
{
    std::vector<int> v;
    BOOST_TYPEOF(v)::iterator it = v.begin();
}

引用返信 編集キー/
■29857 / inTopicNo.7)  Re[4]: テンプレート変数からイテレータ変数の宣言
□投稿者/ uskz (2回)-(2008/12/15(Mon) 22:49:48)
2008/12/15(Mon) 22:50:10 編集(投稿者)
2008/12/15(Mon) 22:50:04 編集(投稿者)

標準ライブラリの大半の型とテンプレートはあらかじめ登録してくれているので,

#include <boost/typeof/std/vector.hpp>

を追加してあげればOKです.
引用返信 編集キー/
■29861 / inTopicNo.8)  Re[5]: テンプレート変数からイテレータ変数の宣言
□投稿者/ あんどちん (33回)-(2008/12/15(Mon) 23:52:19)
STLのコンテナしか受けないのならその処理の部分だけテンプレート関数にするのはダメですか?

#include <iostream>
#include <vector>
#include <list>
using namespace std;

template<typename T> inline void func(T& v) {
for(typename T::iterator it = v.begin(); it != v.end(); ++it) {
cout << *it << endl;
}
}

int main()
{
int ia[] = { 1, 2, 3, 4, 5 };
double da[] = { 1.1, 2.2, 3.3, 4.4, 5.5 };

list<int> il(ia, ia + 5);
vector<double> dv(da, da + 5);

func(il);
func(dv);
}

引用返信 編集キー/
■29864 / inTopicNo.9)  Re[2]: テンプレート変数からイテレータ変数の宣言
□投稿者/ aetos (46回)-(2008/12/16(Tue) 01:44:50)
No29846 (アキラ さん) に返信
> ■No29827 (七篠 さん) に返信
>
> Boost.Typeof使えばできるんですけど

やっぱりあるんだ…
引用返信 編集キー/
■29866 / inTopicNo.10)  Re[3]: テンプレート変数からイテレータ変数の宣言
□投稿者/ 七篠 (14回)-(2008/12/16(Tue) 08:10:29)
みなさん、お返事ありがとうございます。

今回、C++ と STL だけで組もうと思っているので、 Boost は使いません。
興味はあるので、いつか使ってみたいのですが。

No29842 (774RR さん) に返信
> typedef list<int> container_type; // ここを変更するだけでいい

typename typedef list<T>::iterator Iterator;
ここを変えるということでいいのでしょうか?
引用返信 編集キー/
■29867 / inTopicNo.11)  Re[3]: テンプレート変数からイテレータ変数の宣言
□投稿者/ 774RR (260回)-(2008/12/16(Tue) 08:43:09)
ええっと、俺のソースコードそのまま試してみたりした?
してないだろ。そういうコメントが出てくる、っつことは。

list<int> を list<double> にしてみたり vector<int> にしてみたり
っつーことなら
typedef list<int> container_type; を
typedef list<double> container_type; にしたり
typedef vector<int> container_type; にしたり
すれば、それ以外の部分はすべて container_type を使えばいい。
iterator がほしけりゃ container_type::iterator と書ける。
value_type がほしけりゃ container_type::value_type と書ける (int や double になる)

毎回毎回 container_type::iterator と書くのがめんどくさいのなら
typedef container_type::iterator Iterator; としておくのも可能。

なんだけど、俺のコードは脊髄反射で書いた代物なので、実用に供するなら
No29861 あんどちん 氏のコメントと同じく当該処理をすべて template にする。
氏のソースは T として iterator_type が定義してあるクラスのみコンパイルが通る
という代物になっているわけだ。標準コンテナはすべて OK だし、
「前提条件」を満たすような自作コンテナでもうまく動く、ということだよ。
引用返信 編集キー/
■29902 / inTopicNo.12)  Re[4]: テンプレート変数からイテレータ変数の宣言
□投稿者/ 七篠 (15回)-(2008/12/16(Tue) 13:46:54)
お返事ありがとうございます。

No29867 (774RR さん) に返信
> typedef list<int> container_type; を
> typedef list<double> container_type; にしたり
> typedef vector<int> container_type; にしたり
> すれば、それ以外の部分はすべて container_type を使えばいい。
> iterator がほしけりゃ container_type::iterator と書ける。
> value_type がほしけりゃ container_type::value_type と書ける (int や double になる)

必要な型ごとに定義すればいいわけですね。

> No29861 あんどちん 氏のコメントと同じく当該処理をすべて template にする。
> 氏のソースは T として iterator_type が定義してあるクラスのみコンパイルが通る
> という代物になっているわけだ。標準コンテナはすべて OK だし、
> 「前提条件」を満たすような自作コンテナでもうまく動く、ということだよ。

これなら変数を渡せばいいだけなので便利ですね。
ただ、この方法だと処理ごとに関数が必要になってしまいます。

そこで、ラップクラスにイテレータも内包させてしまいました。

このイテレータに先頭値を与える関数 Iterate_Begin
リストの終わりをチェックする Iterate_HasNext
現在イテレータが指し示す中身を取得する Iterate_GetContents

これらを実装し、

List<int> foo;

for(foo.Iterate_Begin(); foo.Iterate_HasNext();)
{
cout << foo.Iterate_GetContents() << endl;
}

こんな感じで使えるようにしました。
いかがでしょうか?
引用返信 編集キー/
■29908 / inTopicNo.13)  Re[5]: テンプレート変数からイテレータ変数の宣言
□投稿者/ 774RR (261回)-(2008/12/16(Tue) 14:17:21)
いいのか悪いのかは実装を見ないとわからないよ。

(とりあえず話を inputiterator に限定しとこう)
・マルチスレッドシステムにおいて同一オブジェクト (foo) に対するループが
 まったく同時に走る場合にまずくないか?
・例外安全についてどれだけ考察されているか?
・インスタンス変数(メンバ変数)とローカル変数 (自動変数にとった iterator) とでは
 アクセス速度が違うんだが性能がきっちり出せるか?

などなどきっちりあれこれ考え済みであるなら問題は無いけどさ。
引用返信 編集キー/
■29926 / inTopicNo.14)  Re[6]: テンプレート変数からイテレータ変数の宣言
□投稿者/ 七篠 (16回)-(2008/12/16(Tue) 16:01:56)
お返事ありがとうございます。

No29908 (774RR さん) に返信
> いいのか悪いのかは実装を見ないとわからないよ。
振る舞いを何も考えずにそのまま実装したものです。
たとえば Iterate_Begin であれば、メンバのイテレータに
メンバのリストの begin の返り値を入れるだけです。

> ・マルチスレッドシステムにおいて同一オブジェクト (foo) に対するループが
>  まったく同時に走る場合にまずくないか?
> ・例外安全についてどれだけ考察されているか?
この二つは全く考えていませんでした。 例外とは、イテレータが
不正な値を参照した状態で中身を返さないように気をつけるといったこと
でしょうか? マルチスレッドについては勉強不足で分かりません。

> ・インスタンス変数(メンバ変数)とローカル変数 (自動変数にとった iterator) とでは
>  アクセス速度が違うんだが性能がきっちり出せるか?
STL の素のリストとラップしたリストで、1 〜 10000 までの数字を文字にして要素として追加し、
すべてコンソールに出力するテストをしてみました。 結果はほとんど
同じでした。(timeGetTime にて計測)

引用返信 編集キー/
■29934 / inTopicNo.15)  Re[7]: テンプレート変数からイテレータ変数の宣言
□投稿者/ 774RR (262回)-(2008/12/16(Tue) 17:13:58)
template<typename T> struct List {
  list<T> list;
  list<T>::iterator it;
  void iterate_begin() { it=list.begin(); }
  bool iterate_isend() { return it!=list.end(); }
  void iterate_next() { ++it; }
};
であるとして。

まずこれだけなら例外に対しては安全 (だと思う:規格書読みきれていない)

次にこれはスレッド安全ではなく、再帰安全でもない。
複数のスレッドから同時に it を操作してしまうと互いに壊しあってしまう。
反復中に呼び出すルーチンから再度 it を操作してしまうと壊れてしまう。
なのでお勧めできない。俺ならこういうコードは書かない。

for (list<T>::iterator it=container.begin(); it!=container.end(); ++it) { ... }
であれば、この it はローカル変数なのでスレッド安全であるし、再帰安全でもある。お勧め。
(反復中にコンテナを書き換える場合は話が違うので除外するものとする)

速度の件なんだけど、メンバ変数と自動変数で1回の反復につき数クロック違うだけだよ。
10000回のループなどでは観測できっこないよ。特に、画面出力などしてれば余計に。
(処理時間のほとんどすべてが画面出力にかかる時間なので)
# だけど C++ ユーザってその数クロックを気にしたりするわけで

で、なぜ処理を(インライン)関数化するのがだめなわけ?
ほんの数行のループ処理だけ template 化する必要がある、とか思っている?
全体を template な関数にしてもいいぢゃん。

引用返信 編集キー/
■29936 / inTopicNo.16)  Re[8]: テンプレート変数からイテレータ変数の宣言
□投稿者/ アキラ (136回)-(2008/12/16(Tue) 17:54:48)
アキラ さんの Web サイト
むしろ、コンテナをfor文で簡単に回したいだけならBoost.Foreachを使えばいいんじゃないかと。
Boost使いたくないなら、私が作った↓をどうぞ。

http://d.hatena.ne.jp/faith_and_brave/20071204/1196760974
引用返信 編集キー/
■29937 / inTopicNo.17)  Re[8]: テンプレート変数からイテレータ変数の宣言
□投稿者/ 七篠 (17回)-(2008/12/16(Tue) 18:01:44)
お返事ありがとうございます

No29934 (774RR さん) に返信
> template<typename T> struct List {
> list<T> list;
> list<T>::iterator it;
> void iterate_begin() { it=list.begin(); }
> bool iterate_isend() { return it!=list.end(); }
> void iterate_next() { ++it; }
> };
> であるとして。
ほぼこれと同じです。 違いはイテレータを進める処理が中身の取得時って事だけです。

> 次にこれはスレッド安全ではなく、再帰安全でもない。
> 複数のスレッドから同時に it を操作してしまうと互いに壊しあってしまう。
> 反復中に呼び出すルーチンから再度 it を操作してしまうと壊れてしまう。
> なのでお勧めできない。俺ならこういうコードは書かない。
ミューテックスで保護するのでは駄目でしょうか?

> この it はローカル変数なのでスレッド安全であるし、再帰安全でもある。お勧め。
変数の保護までする必要があるとなると、結果的にこちらの方が簡潔ですね。
(再帰安全に関しては少し調べてみましたが分かりませんでした)

> 速度の件なんだけど、メンバ変数と自動変数で1回の反復につき数クロック違うだけだよ。
> 10000回のループなどでは観測できっこないよ。特に、画面出力などしてれば余計に。
画面出力なしで 1000000 程まわしたところ、STL の方が 500 ms 早かったです。

> # だけど C++ ユーザってその数クロックを気にしたりするわけで
確かに自分もそういったことが気になりますね。 最近は C# を使っていて、
すごく楽で気に入っていました。 しかし、速度は C++ の方が早いということで、
C++ で C# ライクにコードを書けるように創意工夫中で、今回の質問もその一環です。
C# でのリストなどの型指定は変数宣言時だけなので、
スレッドの問題がイテレータの保護ですむのであれば、出来れば先に提示した
形で扱いたいのですが…
引用返信 編集キー/
■29938 / inTopicNo.18)  Re[9]: テンプレート変数からイテレータ変数の宣言
□投稿者/ 七篠 (18回)-(2008/12/16(Tue) 18:13:52)
お返事ありがとうございます。

No29936 (アキラ さん) に返信
> むしろ、コンテナをfor文で簡単に回したいだけならBoost.Foreachを使えばいいんじゃないかと。
> Boost使いたくないなら、私が作った↓をどうぞ。
>
> http://d.hatena.ne.jp/faith_and_brave/20071204/1196760974
アキラさんのソース見て思い出したのですが、C# でも foreach の
時に型宣言してますね。 そうなると 774RR さんの
for (list<T>::iterator it=container.begin(); it!=container.end(); ++it) { ... }
の方法でも問題ありませんね。

変な所に拘ってたせいで、皆さんを困惑させてしまったかもしれません。
ホントにすいませんでした。 しかし、おかげで納得できる方法が見つかりました。
皆さん、アドバイスありがとうございました!
解決済み
引用返信 編集キー/
■29939 / inTopicNo.19)  Re[9]: テンプレート変数からイテレータ変数の宣言
□投稿者/ 774RR (263回)-(2008/12/16(Tue) 18:32:07)
iterator が1つしかないので反復中に反復かけたくなったら破綻するのに
Mutex で保護も無いもんだ

// こんな感じで iterator が2つ必要な場合に提示コードだとどうにもならない
for (x=c.begin(); x!=c.end(); ++x) {
  y=x;
  for (advance(y,1); y!=c.end(); ++y) {
    // y と x で何かする ...
  }
}
そんなことしない、っつなら別に言うことは無いけど。

引用返信 編集キー/
■29949 / inTopicNo.20)  Re[7]: テンプレート変数からイテレータ変数の宣言
 
□投稿者/ あんどちん (34回)-(2008/12/16(Tue) 22:34:44)
遅レスですが…

No29926 (七篠 さん) に返信
> ほぼこれと同じです。 違いはイテレータを進める処理が中身の取得時って事だけです。
774RRさんのコードのようにイテレータ更新を別メソッドにした方が汎用性が上がると思いますよ。
中身の取得をすると更新されては同じ位置のデータを2回取ることが難しくなります。イテレータ更新はfor文の中で行うでしょうからプログラム行数もまず変わりませんし。

> STL の素のリストとラップしたリストで、1 〜 10000 までの数字を文字にして要素として追加し、
> すべてコンソールに出力するテストをしてみました。 結果はほとんど
> 同じでした。(timeGetTime にて計測)
>
List<T>のインスタンスをローカルに生成していませんか?
その場合List<T>内のイテレータもフレームポインタからのオフセットで参照できるので、イテレータをローカル変数で宣言して処理する場合とほとんど変わらない実行コードが出来ると思います。
あと、コンソール出力も時間計測の中に入れると、その処理時間が大き過ぎて差が出にくいということもあり得ます。

引用返信 編集キー/

次の20件>
トピック内ページ移動 / << 0 | 1 >>

管理者用

- Child Tree -