トップページ⇒tech
1001コメント388KB

【C++】template 統合スレ -- STL/Boost/Loki, etc.

■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさんNGNG
C++ のジェネリックプログラミングの話をしましょう。
以下のスレッドを統合するスレです。

STLスレッド
Part1 http://pc.2ch.net/tech/kako/1004/10042/1004287394.html
Part2 http://pc3.2ch.net/test/read.cgi/tech/1026793823/

【C++】Boost使い集まれ!
http://pc3.2ch.net/test/read.cgi/tech/1033830935/

Generic Programming with C++ Template
http://pc.2ch.net/tech/kako/1008/10085/1008593126.html

関連スレ、その他リンクは >>2-5 あたりに。
0111デフォルトの名無しさんNGNG
>>107
逆に、IDから元の型を取得することはできないの?

float f = 1f;
int i = (class_id(int))f;

キャストに使えたりするとうれしい。
0112デフォルトの名無しさんNGNG
よく使う foo とか bar とかって、RFC で定義されてたんだな。
知らなかった。
http://www.puni.net/~mimori/rfc/rfc3092.txt
0113デフォルトの名無しさんNGNG
jokeだろ
0114デフォルトの名無しさんNGNG
>113
しっ!!
0115デフォルトの名無しさんNGNG
うお!IPってデータリンク層に鳩使っても使用可能なんだってさ!
RFC勉強になりすぎ。
0116107NGNG
ネタ元は
http://lists.boost.org/MailArchives/boost/msg37791.php
ね。

>>111
それが出来ると typeof の完成なんだけど、思いつかないっす。
105氏のType_ofみたいに、必要なクラスのid - typeのマッピングを
全部手で書いていくくらいしか。何か上手い手はないかな。
0117105NGNG
ttp://www3.to/typeof
にとりあえず上げてみました。
中を見ると分かるけど

>>111
int i = (type_of_id( class_id(int) ))f;
でできます。でもType_ofで登録した物にしか使えません。

>>107
ちょこっと追加として
int addfunc(int,int);
type_of_declare(addfunc(int,int),aa);
std::cout << aa;
とかできるようにした。(定義場所わかりにく...

>>107(116)
入れ子の式テンプレートでできないかと思ったけど撃沈...。(以下、略
template <typename T> struct Type_of_collection
{
template <int N> struct Type_of_Num;
struct Type_of_Num<class_id(T)> { typedef T type;};
};
0118デフォルトの名無しさんNGNG
Intel C++ Compiler 7.0 age

ttp://www.xlsoft.com/jp/products/vtune/icppwin.html
0119デフォルトの名無しさんNGNG
質問です。VC++6.0で

#include <list>
using namespace std;
void main(){
list<list<int>> a:
}
というのでエラーがでます。
listのlistを作るにはどのようにしたらいいのでしょうか?
0120デフォルトの名無しさんNGNG
>>が引き篭もりなのです
0121デフォルトの名無しさんNGNG

>list<list<int>> a:
色々違ってるな。

0122デフォルトの名無しさんNGNG
>120

ありがとうございました。
直りました。
0123デフォルトの名無しさんNGNG
>>118
ただなの?
0124デフォルトの名無しさんNGNG
>C++ Compiler 7.0 for Windows \55,000
0125デフォルトの名無しさんNGNG
std::vectorのstd::sortが予想外に速い。インライン展開の賜物か。

const int N = 2000000;
int cmp(const void *, const void *);

int main()
{
static double d[N];
std::vector<double> vd;
std::clock_t ti;

std::srand(0);
for (int i = 0; i < N; i++) d[i] = std::rand();
std::srand(0);
for (int i = 0; i < N; i++) vd.push_back(std::rand());

ti = std::clock();
std::qsort(d, N, sizeof(double), cmp);
std::cout << "qsort = " << std::clock() - ti << std::endl;

ti = std::clock();
std::sort(vd.begin(), vd.end());
std::cout << "sort = " << std::clock() - ti << std::endl;
}
0126デフォルトの名無しさんNGNG
int cmp(const void* a, const void* b)
{
if (*static_cast<const double*>(a) < *static_cast<const double*>(b)) return -1;
else if (*static_cast<const double*>(a) > *static_cast<const double*>(b)) return 1;
return 0;
}

qsort = 906
sort = 734
0127デフォルトの名無しさんNGNG
intだと

qsort = 702
sort = 328

差が開く。
0128デフォルトの名無しさんNGNG
intでcmp()を

int cmp(const void* a, const void* b)
{
return *static_cast<const TYPE*>(a) - *static_cast<const TYPE*>(b);
}

に換えたらちょっと速くできるけどまだsort()の方が速い。よくできてるなあ。

qsort = 562
sort = 344
0129デフォルトの名無しさんNGNG
あっごめん、環境はBorland-C++5.6.2(STLport装備)ね。
0130デフォルトの名無しさんNGNG
Win98SE、VC6SP5、PentiumIII-800。
STL は VC6 付属のもの。
コンパイラ付属のソースをインライン展開しまくった my_qsort でもやってみたよ。

double:
my_qsort = 4340
qsort = 4720
sort = 1760

int:
my_qsort = 1540
qsort = 3240
sort = 830

int (quick cmp):
my_qsort = 1430
qsort = 2520
sort = 830

どうも、インライン展開うんぬんより、アルゴリズムが根本的に違ってるように見える。
STL のソートって何ソートなの?
0131 NGNG
sort って比較と入れ替えが処理のメインだから、そこが関数呼び出しになって
しまって最適化されない qsort は正直かなりのオーバーヘッドがあると思う。
0132デフォルトの名無しさんNGNG
>>130
qsort の方はよく知らんが、STL の方は、

基本はクイックソート
pivot には先頭・ど真ん中・末尾の要素の中央値を使う
要素数が小さくなってきたら挿入ソートに切り替える
あと、最新版では再起が深くなってきたらマージソートに切り替えるって機能も付いてたと思われ。
0133デフォルトの名無しさんNGNG
標準のstd::logical_and、std::logical_orの使い方がよくわかりません。
参考書を読むと、標準にはないbinary_composeと組み合わせて使うと
書いてあるのですけど、どういう意味なのでしょうか?
0134デフォルトの名無しさんNGNG
>>131
130 の 3 行目は読んでくれたか?
> int (quick cmp):
> my_qsort = 1430
> sort = 830
その関数呼び出しのオーバーヘッドが無い状態で、これだけ差があるの。

>>132
VC6 付属の qsort.c については、
> pivot には先頭・ど真ん中・末尾の要素の中央値を使う
> 要素数が小さくなってきたら挿入ソートに切り替える
これと同じっぽい
要素数 8 以下で挿入ソートに入る。
ただし、マージソートはやってなくて、再帰は使わずに goto で戻してる。

ネックになりそうなのは、STL の場合のように代入演算子が使えないので、
char 単位にデータ転送しているところかな。
でも、それを無理矢理 int 決め打ちの swap にしても、まだ sort() のが
速い。
> my_qsort = 1100
後は何だ?
0135デフォルトの名無しさんNGNG
>>133
binary_composeにはSGIのSTLやSTLportで定義されている。std::compose2
というヘルパ関数を持つ。

例えば _1 < 1 || 3 <= _1 という関数オブジェクトを作るには

std::compose2(std::logical_or<bool>(), std::bind2nd(std::less<int>, 1), std::bind2nd(std::greater_equal<int>, 3))

とすればよい。

boostではネーミングが異なり、boost::compose_f_gx_hyとなっている。
0136デフォルトの名無しさんNGNG
> ネックになりそうなのは、STL の場合のように代入演算子が使えないので、
> char 単位にデータ転送しているところかな。

double が異様に遅いのはこのせいだな。
インライン展開しまくり、かつ代入演算子に変えたら、sort() に肉薄した。

my_qsort = 1965
qsort = 4715
sort = 1753

でもやっぱり sort() のが遅いけど。


あと、↓でより正確に測れる。

#pragma comment(lib , "winmm.lib")
#define clock_t DWORD
#define clock() timeGetTime()
0137デフォルトの名無しさんNGNG
> でもやっぱり sort() のが遅いけど。

sort() のが速いけど。ですた。
0138デフォルトの名無しさんNGNG
> boostではネーミングが異なり、boost::compose_f_gx_hyとなっている。

スマソ。boost::compose_f_gx_hxとなっている。に訂正します。
0139デフォルトの名無しさんNGNG
>>136
そうだったのか。あらゆる型に汎用にするために、charでアラインされた
転送単位を持つためにqsort()は遅いのか。

ということはcharでsortするとそんなに差は出ないはずだな。

・・・・やってみた。

qsort = 265
sort = 282

測定誤差により、逆転する事もあるが、大ざっぱに測定するとqsort()の
方が速くなった。納得。
0140デフォルトの名無しさんNGNG
STLとboostを一度同じ土俵に上げて、そのよさを比較し、
なし崩しにboostを認めようという作戦ですか?

私は認めませんよ!>boost
0141boostNGNG
>>STL
ごめんなさい
0142デフォルトの名無しさんNGNG
標準 boost → SB
0143デフォルトの名無しさんNGNG
次期STLは間違いなくboostからいくつかの機能を取り入れるだろうに。
0144小技NGNG
template< class T, class U >
U hoge( T foo, U* = NULL )
{
...
}

// 使い方
hoge<string, int>( "第二引数はダミー" );
0145デフォルトの名無しさんNGNG
>>144
これのどこが技なのか・・・・・
0146デフォルトの名無しさんNGNG
よけーなオーバーヘッド食いそうだ
0147107NGNG
>>117
> ttp://www3.to/typeof
素晴すぃ。

結局friendで勝手に定義を挿入するしかなさそう、と思ってその方向で
弄ってたんだけど、id_counter と違ってsizeof以上の情報を
オーバーロードされた関数からとってこなきゃいけないのがうまく行かなくて撃沈続き…。
0148デフォルトの名無しさんNGNG
>>144
VC6対策か?
0149デフォルトの名無しさんNGNG
>>145-146
わからんのか?ヒントは返り血
0150デフォルトの名無しさんNGNG
template<class T, class U>
U hoge(T foo, U* up = 0)
{
return *up;
}

int main()
{
hoge<std::string, int>( "第二引数はダミー" );
}

としてみてもなあ。。。。intが無駄に使われているような気がして
ならない。
0151デフォルトの名無しさんNGNG
>150
じゃなくて、ふつーに書くと返り値の型が異なるだけの関数は多重定義できん
という話でしょ。

template じゃなくても良いんだが

int foo();
void foo();

これは NG だが、

int foo(int);
void foo();

これなら行ける。

> intが無駄に使われているような気がして
とりあえず最適化有効にしてアセンブラ出力させてみ。
0152デフォルトの名無しさんNGNG
inline化されたら無駄な引数はなかったことになるだろうねえ
0153デフォルトの名無しさんNGNG
つまり、第二引数の型を変えて多重定義するためというものなのか?
今いち存在意義がわからんが・・・・・・
0154デフォルトの名無しさんNGNG
俺も今一分かってないんだが,

int GetValue("キー")
string GetValue("キー")

みたいなことができるってことかい?
0155154NGNG
ごめん。なんか違うみたい・・・
具体的な使用例をあげてみてくれないかい?
0156デフォルトの名無しさんNGNG
>>153
templateの特殊化したいときとか使えるけど?

>>155
>>151に書いてあんだろ?アホか?
0157デフォルトの名無しさんNGNG
>>156
155 はそんなことをする理由を訊きたがっているんだぞ。

無理やり使いどころを考えると、template クラスで Factory 関数を使うときか?
0158154NGNG
>>157
そういうことです
(だから>>154でわざわざ”GetValue"という関数名を使ったのですが伝わらなかったようで・・・)

>無理やり使いどころを考えると、template クラスで Factory 関数を使うときか?
うーん。確かに無理やりですね。

Widget MakeWidget() ※Widgetは基底クラス

ってするもんじゃないでしょうか。

同じ関数名で返り値が違うってのがそもそも想像できないんですが・・・。
0159154NGNG
連カキすまん。

利用法が無いなら無いでいいんです。
「こういうこともできるよ」って例なのだとしたら。

でも実際に使いどころがあるんでしたら聞いてみたいのです。
0160デフォルトの名無しさんNGNG
>>151
それなら

template<class U, class T>
U hoge( T foo )
{
...
}
// 使い方
hoge<int>( "第二引数なんざ要らん" );

で十分では?古いヘタレコンパイラでどうなるかは知らんが。
0161デフォルトの名無しさんNGNG
>158
> 同じ関数名で返り値が違うってのがそもそも想像できないんですが・・・。
template を使って Mixin (あるいは Strategy パターン) をを書くときに使える。
0162デフォルトの名無しさんNGNG
>160
それだと、明示的に型を指定する必要があるのが難だなぁ。

パラメタとして関数オブジェクト、関数ポインタ、ともかく () つければ処理して
くれるモノ何でも渡せるようにしておくと、コードの汎用性が上がる(場合がある)。
0163160NGNG
>>162
引数をtemplateにして型指定を緩くしとくと嬉しい、というのはその通りだけど、
この場合関係ないでしょ。(>>144のも同じく明示的な型指定が必要)

違うのは返値の型のみ、という関数を作りたいとき (例えばModern C++ Design の
Factoryパターンの話とか) の話でないの?
0164デフォルトの名無しさんNGNG
>>160
が通るコンパイラが有るなら教えてくれ。
0165デフォルトの名無しさんNGNG
>164
ないだろう。class を typename にすれば通るけど。
0166デフォルトの名無しさんNGNG
class_idだけど、テンプレートの特殊化のときにちょっとだけ違うためだけに
同じもの作らなくて済ませることができそうな気がする。
これって実行時に判定してるのかな?
Tって静的だけどデバッガで見るとswitch文の中は最適化されてないみたいなんです。

template <typename T> struct FFF
{
FFF(T a=0)
{
switch( class_id(T) )
{
case class_id(char):
std::cout << "char" << std::endl;break;
case class_id(short):
std::cout << "short" << std::endl;break;
default:
std::cout << "other" << std::endl;
}
}

};

template <> struct FFF<int>
{
FFF(int a=0)
{
std::cout << "int" << std::endl;
}
};
0167続きNGNG
int main()
{
//出力結果
FFF<int> fff1; //int
FFF<char> fff2; //char
FFF<short> fff3; //short
}

0168デフォルトの名無しさんNGNG
>>164
VC++.NET と Bcc5.51 と DigitalMarsC++8.31 と
g++3.2 と g++2.95 と Comeau C++4.31 と Intel C++6.0 では通ったが?
通らないコンパイラを教えてくれ。
0169デフォルトの名無しさんNGNG
うっひょっひょ( ゚∀゚ )
0170続きNGNG
class_id(char) ->1 (enum定数)
class_id(short) ->3 (enum定数)
直接は飛んでないけど、結局同じなんで問題ないか。
(↓最適化なしのものVC)最適化すると変わるんだろうか...。
; 168 : FFF<char> fff2;
mov DWORD PTR -416+[ebp], 1
cmp DWORD PTR -416+[ebp], 1
je SHORT $L23144
cmp DWORD PTR -416+[ebp], 3
je SHORT $L23145
jmp SHORT $L23146
0171デフォルトの名無しさんNGNG
>>153
たとえば >>53
0172デフォルトの名無しさんNGNG
>>21
ひどいことを言うなよ。お前だってアホだったろうが
0173デフォルトの名無しさんNGNG
>>172
ひどいことを言うなよ。
0174デフォルトの名無しさんNGNG
>>168
確か>>164の脳内コンパイルだと通りません。
0175デフォルトの名無しさんNGNG
ネタがないとスレが荒むな。
0176デフォルトの名無しさんNGNG
それもあるけど、昔と比べると荒れすぎ。
0177164NGNG
>>168,174
悪りィ、TとUが逆転してるのに気付かんかった。
っていうかテンプレ引数の交換は気付きにくいからやめい。
0178デフォルトの名無しさんNGNG
>>177
やめい、って交換しなきゃ第二引数が省略できんだろ。
0179デフォルトの名無しさんNGNG
>>178

template<class T, class U>
T hoge( U foo )
{
...
}

hoge<int>("できますが何か?");
0180160NGNG
>>177
ああ、なるほど。混乱させてすまなんだ。

U を使うのって Undeducible か何かの略かと思ってたんで>>144と
同じに返値U、引数T、になるようにtemplateの方を変えたんだけど、
Tの次はUってことか。自分では2引数以上のtemplateを書くときは
T1、T2、 T3 ... なのでなぁ。
0181デフォルトの名無しさんNGNG
>>179
コロンブス的な発想にチトワラタ(w
0182デフォルトの名無しさんNGNG
素朴な疑問なんだけど
template<class T, class U>
を
template<typename T, typename U>
とは書かないの?
0183160NGNG
>>182
個人的には、
・タイプ数減らしたい時はclass。
・template template parameter は class と書くので、
 何となく全部 class で統一したい気分の日は class。
・マジメに書くときはtypename。
0184デフォルトの名無しさんNGNG
漏れは最初に覚えたときにclassのみだったから
テンプレート引数はclassのみ使用。
typenameは
typedef typename T::iterator iterator;
とがぐらいしか使わない。
0185デフォルトの名無しさんNGNG
>>184
漏れはtypenameに直した。
ってか,intとかにも対応するのにclassって気持ち悪いんだよな。C++のintはクラスじゃないし。
0186184NGNG
>>185
気持ちは分かる。
0187デフォルトの名無しさんNGNG
昨夜、”C++ Templates" をゲット
まだChapter 3までしか読んでないけど、なかなか良さげ
0188デフォルトの名無しさんNGNG
>>187
どこの出版社?(・∀・)イイ?
0189デフォルトの名無しさんNGNG
>>189
Addison-Wesley だが……出たばっかの洋書でふ
0190189NGNG
× >>189
○ >>188
0191デフォルトの名無しさんNGNG
>>189
ありが�d。俺も本屋行って見てくるよ。
0192デフォルトの名無しさんNGNG
>Addison-Wesley だが…
Addison-Wesley キタ─wwヘ√レvv~(゚∀゚)─wwヘ√レvv~─ !!!!
Addison-Wesley、もう大好き♪
分かりやすいし、詳しいし…。
0193デフォルトの名無しさんNGNG
>>183
俺は int などのプリミティブ型も引数に取る場合には typename, クラスしか
引数に取らん場合には class にしてる。まー、趣味の問題だね。
0194デフォルトの名無しさんNGNG
typename と class は全く同一だと聞いた事があるが・・・どこでだっけ?
0195デフォルトの名無しさんNGNG
本屋行ってみたが、洋書は置いてないと言われた。(´・ω・`)ショボーン
日本訳が出るまで最低1年はかかるからなー。
0196デフォルトの名無しさんNGNG
typename自体が無いしょぼーいコンパイラも世の中には存在する。
0197デフォルトの名無しさんNGNG
>196
まだ使ってるのか… 御愁傷様です。
0198デフォルトの名無しさんNGNG
>>194
全く同一だよ。だからみんなして趣味の問題とか個人的にはとか言ってるわけ。

>>195
出たばっかりの洋書はWebで買った方が良いと思う。
0199デフォルトの名無しさんNGNG
VC6sp5にも移植が出来たみたいです
http://fara.cs.uni-potsdam.de/~kaufmann/?page=lokiport
0200デフォルトの名無しさんNGNG
>>199
がいしゅつ
http://pc3.2ch.net/test/read.cgi/tech/1035005882/766
0201デフォルトの名無しさんNGNG
boost::lexical_castで、スペースを含む文字列を変換すると例外が
出ますな。

std::cout << boost::lexical_cast<char*>(std::string("abc def")) << std::endl;
std::cout << boost::lexical_cast<std::string>("abc def") << std::endl;

boost::lexical_castはstd::stringstreamを使って実装しているので、
>>演算子や<<演算子がスペースを区切り文字とみなしてしまう故らしい。
何とかして欲しいですな。
0202デフォルトの名無しさんNGNG
>>201
http://groups.yahoo.com/group/boost/files/lexical_cast_proposition/
…では直ってるので1.30では修正が取り込まれると思いたい。
と言いながら結局1.29には取り込まれなかったけどなぁ。
0203デフォルトの名無しさんNGNG
落ちそうなので一回ageます。
0204デフォルトの名無しさんNGNG
昨日からSTLの勉強をVC++.Netで始めました。
まだ、わかってない部分が多いのですが、質問させてください。

汎用クラスを定義する際、通常のクラス定義のように CSample.h , CSample.cpp
のように宣言と定義を別ファイルにはできないのですか?

ウィザード利用によるクラス定義(一般クラスの作成手順)を行って、
後で、Template <class T> 文を
class CSample
宣言の前につけたり、いろいろしましたが、コンパイルが通りません。
(中間オブジェファイルができません)

結局、定義と宣言を分けないでヘッダファイルのみで全てを記述すれば、OKでした。

実際に汎用クラスを利用する際には、利用箇所によって型決定する事を考えれば
当然のような気もするんですが、そうなんでしょうか?

もしそうなら、複数のファイルで、同一の汎用クラスを利用する際は、利用するファイルに、
定義した汎用クラス全文をインクルードすることになるんでしょうか。
0205デフォルトの名無しさんNGNG
>>204
>複数のファイルで、同一の汎用クラスを利用する際は、
>利用するファイルに、定義した汎用クラス全文を
>インクルードすることになるんでしょうか
そうです
0206デフォルトの名無しさんNGNG
>>204
何度もガイシュツだが、exportキーワードを完全にサポートしている処理系
でなければ、template文の宣言と実体を別のファイルに分けて書くことはできない。

もしexportキーワードが有効であれば、実体部をライブラリにできることになる。
0207204NGNG
やっぱりそうだったんですね。
しかも、ガイシュツとのことで、もうしわけないです。
ありがとうございました。がんばってみます。
0208デフォルトの名無しさんNGNG
物の本によれば、//1の書き方は正しくなく、//2のように書かなければならないと
いう意見があるのですが、どちらが正しいのでしょうか。
ちなみにコンパイルはどちらでも通ります(gcc3.2)。

struct Test {
template <typename T, typename U>
void func(T x, U y) {
std::cout << typeid(x).name() << ' ' << typeid(y).name() << std::endl;
}
};

int main()
{
Test t;
t.func(1, 1); // as <int, int>
t.func(1.1, 2.2); // as <double, double>
t.func<int, double>(2, 3.3); //1
t.template func<int, double>(2, 3.3); //2
}
0209デフォルトの名無しさんNGNG
>>208
メンバ関数テンプレートはtと同一のスコープの時は
大丈夫ですが、パラメータとしてtをどこかへ渡すと
t.template と書く必要があります。
0210デフォルトの名無しさんNGNG
>>209
大丈夫なようですが・・・・・意味を勘違いしてるかな?

struct Test {
template <typename T, typename U>
void func(T x, U y) {
std::cout << typeid(x).name() << ' ' << typeid(y).name() << std::endl;
}
};

void abc(Test& t)
{
t.func(1, 1.1);
}

int main()
{
Test t;

abc(t);
}
■ このスレッドは過去ログ倉庫に格納されています