トップページtech
985コメント328KB

Generic Programming with C++ Template

■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさんNGNG
C++ による Generic Programming の話をしよう。

参考図書:
Modern C++ Design
Andrei Alexandrescu, Addison-Wesley, ISBN:0-201-70431-5
(訳書: ピアソン・エデュケーション, ISBN:4-89471-435-3)
http://cseng.aw.com/book/0,,0201704315,00.html

Generic Programming - STL による汎用プログラミング
Matthew H. Austern, ASCII, ISBN:4-7561-3441-6

関連スレッド:
C++相談室 Part3
http://pc.2ch.net/test/read.cgi/tech/1003832761/

STL スレッド
http://pc.2ch.net/test/read.cgi/tech/1004287394/
0322デフォルトの名無しさんNGNG
>>321
> boost-dev(?) の ML 読んでんの?すげー。
全部は追ってないし、開発にも参加してない。必要そうなヤツだけ斜め読み
だよ。(C++ は仕事道具だし)

Boost -- Boost mailing list
http://lists.boost.org/mailman/listinfo.cgi/boost

> cppmlぐらいなら分かるんだけどさすがにそんなところ
cppml ではなくて cppll かしらん?

俺は cppll は最初は読んでたんだが、エピスが検定試験云々言い始めた頃に
S/N 比が許容値を下回ったので切った。最近はどうなん?>読んでる人
0323デフォルトの名無しさんNGNG
>>322
cppIIは今も取ってるが未読が1253通(藁
全然読んでないよ。
エピス氏はコード出して技術的な話をしているうちはいいが、
取り巻きも含めて雑談モードに入るとうるさいからな。

重鎮扱いで誰もつっこめないし。
0324デフォルトの名無しさんNGNG
>>323
俺も彼の言語感覚についていけないクチだね…
自動で s/ぢ/じ/g してから読めば少しはマシになるかな(w
0325デフォルトの名無しさんNGNG
うむ。
10代、せめて20代前半ならまだ許せるが、
某本で素顔の写真見ちゃったからなぁ・・・
0326デフォルトの名無しさんNGNG
あの写真はショックだったという人
わりといますね。典型的な(略)
0327デフォルトの名無しさんNGNG
だれかvcppかcppIIでエピス当てにうざいってレス付けてくれないか。
漏れは怖くてできない

電柱○家
Tit○w
あ○る

あたりが突っ込んできそうだな。
「いきなり出てきてあんたの方が役に立ってない」とかいいながら。
0328デフォルトの名無しさんNGNG
すとーるまんみたいな感じ?
0329デフォルトの名無しさんNGNG
全然。
0330デフォルトの名無しさんNGNG
テンプレートと
http://www.csg.is.titech.ac.jp/~chiba/opencxx/html/index.html
これとの組合せでたのしいことになったりしませんか?
0331デフォルトの名無しさんNGNG
>>330
なにこれ?
0332デフォルトの名無しさんNGNG
C++でリフレクションが使えるようになる(前)処理系
0333デフォルトの名無しさんNGNG
>>322
あのMLでは「低いS/Nの中からいかに情報を取り出すか」というのも重要なテーマです(藁
うまいフィルタ作れないかな。もちろんcppで。
0334デフォルトの名無しさんNGNG
C++ Builderってバージョンあがってもう少し使えるようになるかと思ったら
テンプレート周辺にバグがあるんでしょ?がっかり。
しっかりしてくれよ、Borland。期待してるんだから。Pascal以外の言語もがんばってくれよ。
0335デフォルトの名無しさんNGNG
>>334
えっ?初耳。ソースはどこかにありますか?教えて下さい
0336デフォルトの名無しさんNGNG
>>333
struct pr : public std::binary_function< string, string, bool>{
bool operator()(const string& x, const string& y)const{
return search(x.begin(), x.end(), y.begin(), y.end()) != x.end();
}
};

vector<string> articles;
・・・

articles.erase(remove_if(articles.begin(), articles.end(), bind2nd(pr(), "ぢ")), articles.end());
articles.erase(remove_if(articles.begin(), articles.end(), bind2nd(pr(), "ちう")), articles.end());
0337デフォルトの名無しさんNGNG
いっそのこと、
articles.erase(remove_if(articles.begin(), articles.end(), bind2nd(pr(), "FUKUDA Fumiki")), articles.end());
で。

0338デフォルトの名無しさんNGNG
>>334
えっ?猫耳。
0339デフォルトの名無しさんNGNG
>>338
えっ?愛猫。
0340デフォルトの名無しさんNGNG
>338-339
つまんねーよきみら
0341デフォルトの名無しさんNGNG
http://osl.iu.edu/~tveldhui/papers/Template-Metaprograms/meta-art.html

すごい!!
0342デフォルトの名無しさんNGNG
VC7へぼい・・

template<class T> void swap(T& x, T& y) {}
template<class T> void swap(vector<T>& x, vector<T>& y) {}

これコンパイル通らないんだよね・・
プログラミング言語C++ではこういう書き方してるのに。
0343デフォルトの名無しさんNGNG
>>342
using namespace std; を外して、std::vector にしてごらん。
0344デフォルトの名無しさんNGNG
あげげ
0345デフォルトの名無しさんNGNG
おまえらに質問。

最近関数オブジェクトがおもしろくてしょうがないんだけど、
引数がいっぱいあるメンバ関数をもつクラス T があるとして、
std::vector<T> t(100);
std::for_each(t.begin(), t.end(), &T:func);
みたいなのを引数渡ししつつぐるぐるやる方法はないかな。
mem_funcだとうまく引数が渡せないので、引数をなんとかする
関数オブジェクトをいっこつくってぐるぐるするしかないと思うんだけど、
いざコードを書こうとするとかっこわるくていかんのです。

0346デフォルトの名無しさんNGNG
どっちかというとSTLスレで聞くべきだった。
sage鬱

0347デフォルトの名無しさんNGNG
>>345
boost::bindとboost::mem_funとかで出来るんじゃないか?
0348デフォルトの名無しさんNGNG
>>347
たとえば引数が三つあるメンバ関数を考えたとき、
すべての引数に値を渡せるかな?

0349デフォルトの名無しさんNGNG
>>348
3つのうち2つが固定なら出来るんじゃないか?
0350デフォルトの名無しさんNGNG
>>349
ふむ。ちと試してみるよ。
ありがとん

0351デフォルトの名無しさんNGNG
>>343

template<T> void swap(T& x, T& y) {}
template<T> void swap(Class<T>& x, Class<T>& y) {}

2個のオーバーロード関数があいまいで最適な変換ができません。

STLソースではこうなってる模様
template<class T> Class {
public:
friend void swap(Class& x, Class& y) {}
};

でもこれでは既に他の名前空間にあるswapを特殊化できない罠。
なんかおかしくない?
おかしいのは漏れ?
0352デフォルトの名無しさんNGNG
>>351
たぶん、キミがおかしい。
VC7 のことはよくわからんけど、ふつう swap は <algorithm> の中で
次のように定義されているはず:
namespace std{
template<class T> inline void swap(T& x, T& y) { … }
}
で、何か標準ヘッダーをインクルードして、using namespace std;
してるでしょ? それで、1行目の swap とバッティングしてるんだと
思うけど。
ちなみに、2行目の swap は関係ない。それを外してもエラーが出るん
じゃない?
0353デフォルトの名無しさんNGNG
お手軽だからって
using namespace std はやめよーよ。
0354デフォルトの名無しさんNGNG
>>352
例が悪かった・・
swapじゃなくてなんでもいいです。
とにかくテンプレート関数をクラステンプレートで特殊化しようとすると
特殊化優先順位で弾かれる。
名前空間とは関係ない問題です。(これが後々関係してくるが)
0355デフォルトの名無しさんNGNG
具体例を書くよ

template<class T> class Class {};
template<class T> void func(T& x, T& y) {}
template<class T> void func(Class<T>& x, Class<T>& y) {}

void main() {
Class<int> x, y;
func(x, y);
}

error C2667: 'func' : 2 個のオーバーロード関数があいまいで最適な変換ができません。

で、

template<class T> class Class {
public:
friend void func(Class& x, Class& y) {}
};
template<class T> void func(T& x, T& y) {}

これならOK。VC7のSTLもこのパターンで実装されてる。
でも例えばfuncとClassが違う名前空間にあると
このパターンは成り立たない。色々試したがダメだった。
具体的にはstd::swapなんかを
自作のテンプレートクラスで特殊化しようとした場合なんかに
困るわけなんだな、これが。
0356デフォルトの名無しさんNGNG
なんか、テンプレートでいくらがんばっても
あんまり実りが無い感じ。
0357デフォルトの名無しさんNGNG
>>355
前半部分、13.5.1(p.404) によって後者が選ばれなきゃいけない話?
gcc 2.95ではちゃんと選ばれたよ。
0358デフォルトの名無しさんNGNG
>>357
C++の本を見る限りではそのgccの動作が正しいと思うんだけど。
VC7では選ばれる以前にコンパイルエラーになる。
多分、テンプレート関数とクラステンプレートで特殊化したテンプレート関数の
特殊化優先順位が等しいからこんなことになる。
これだったらすぐ直りそうなもんだからSPで直してほしい・・
0359デフォルトの名無しさんNGNG
メーカーの製品がこの程度の品質って、
C++のテンプレートの仕様を把握するのが一苦労って事なのかな?
0360デフォルトの名無しさんNGNG
上記の話、VC6でも確認。前からああみたいだ。

違う名前空間の関数を特殊化するなという意味だろうか。
Javaみたく階層的に名前空間分けてたら
同一プロジェクトでも同じ問題が発生するが・・
共通関数を使わずメンバ関数を使えという話になるんだろうけど
それだとSTLのうまみも半減だわな

ところでクラステンプレートをクラステンプレートで特殊化って
C++的に可能なの?VCではダメだった。
0361デフォルトの名無しさんNGNG
gccは3.0になってからその辺の構文的な要素は完全対応してるのかな?
0362デフォルトの名無しさんNGNG
>>355
Borland-C++ 5.6では正しくコンパイルできますた。
0363デフォルトの名無しさんNGNG
SDLがブレーク? フン、しねーよ。少なくともあなたには必要ないと思われ。
0364デフォルトの名無しさんNGNG
age

0365デフォルトの名無しさんNGNG
Lokiマンセー!!!
でDLしたらVC.NETじゃコンパイルできねージャン!!
氏ねMS!IDEばっか凝ってねーでコンパイラ改良しる!
0366デフォルトの名無しさんNGNG

 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄」
―――――――――――――‐┬┘
                        |
       ____.____    |
     |        |        |   |
     |        | ∧_∧ |   | C++を窓から投げ捨てろ
     |        |( ´∀`)つ ミ | 
     |        |/ ⊃  ノ |   | C++
        ̄ ̄ ̄ ̄' ̄ ̄ ̄ ̄    |    




--------------------------------------------
0367デフォルトの名無しさん NGNG
>>365
そもそもMSがcl.exeをANSIに完全対応させる気がないのだとしたら
どういう事態になるんだろう。
0368デフォルトの名無しさんNGNG
ANSIが規格をねじ曲げれば一件落着。
0369デフォルトの名無しさんNGNG
関数ポインタの配列とenumの関係で質問です。

enum {HOGE,MOGE,MONA,SAGE};
void hoge(void);
void moge(void);
void mona(void);
void sage(void);

typedef void (*FUNC)(void);
FUNC func[] = {hoge,moge,mona,sage};

こんな感じで、HOGEのときはhogeを呼ぶ、みたいに対応させてます。
このとき、enumの順番を変えたら、それに応じてfunc内の関数順番を
手動で変えるのがわずらわしいのです(enumとfuncは別ファイルです。
includeして、見えるようにはなってますけど)。
enumの順番に沿って、対応する関数がfunc内で自働的に並んでいて欲しいのです。
コンパイル時点では順番は確定しているんですから、テンプレートを
ごりごり使いこなせる人間ならできるんじゃないかと淡い期待を
持ってるんですが、どうにかして出来ませんでしょうか?
0370デフォルトの名無しさんNGNG
無理
不可能
0371デフォルトの名無しさんNGNG
>>369
なぜ順番を変えようとする?
0372デフォルトの名無しさんNGNG
数が多いなら、excelのシートに関数名とenum識別子をかいといて
VBAかなにかでボタン一個でソース吐くようにしとけば?

俺だけかもしらんが、よくやってるよ。

その場限りならセルに文字列適当に連結する式かいてコピペ、とかもやるし。
0373デフォルトの名無しさんNGNG
なぜ順番を変えるのかは突っ込まないで置こう。
見栄えが気にくわなくてあっち入れ替えたりこっち動かしたりする時期があるもんさ。
0374デフォルトの名無しさんNGNG
perlスクリプトで自動で吐くようにすればいいやん
0375デフォルトの名無しさんNGNG
ちょっと面倒だけど、こんなん駄目?

#include "stdafx.h"

template< int > struct Function{};
#define DEF_FUNC( index, func ) template<> struct Function<index>{ \
static void call(void){ func(); } }

enum {HOGE,HAGE,};
void hoge(){puts("hoge");}
void hage(){puts("hage");}

DEF_FUNC( HOGE, hoge );
DEF_FUNC( HAGE, hage );

int main(int argc, char* argv[])
{
Function<HOGE>::call();
Function<HAGE>::call();
return 0;
}
0376375NGNG
ガーン!
今頃気づいたけど、呼び出し時のインデックスはコンパイル時には確定してないのか・・・じゃ駄目だ。
0377375NGNG
上のを修正。
ちょっとオーバーヘッドがあるけど、
(テンプレートクラス内のcallをfuncへのポインタに出来ればいいんだろうけど、俺はやり方知らない。)

void (*funcs[])(void) = {
Function<HOGE>::call,
Function<HAGE>::call
};

int main(int argc, char* argv[])
{
for( int index = HOGE; index<=HAGE; ++index )
{
funcs[index]();
}
return 0;
}
0378デフォルトの名無しさんNGNG
> void (*funcs[])(void) = {
> Function<HOGE>::call,
> Function<HAGE>::call
> };

それだと結局、enumを
 enum {HAGE,HOGE,};
に変えられたときにマズーではないか?
0379375NGNG
ぐわぁ!
やっちまった(藁
0380デフォルトの名無しさんNGNG
>>375-377
ちょっとなぁ、という気がする。
自分が書くにはいいが、人には見せられない。

そもそも、見栄えを気にする(順番を入れ替える)んだから、
その書き方はいいとは思えない
0381375NGNG
>>380
つーか普通はこんなことしねぇって。
0382375NGNG
こら待て、今気づいたんだが、375でいいじゃねぇかよ。
enum値と対応させるってことは配列のインデックスは手打ちでenumの値を書くってことだろ?
インデックスが実行時に決まるならenumに対応させる意味もないし。
0383デフォルトの名無しさんNGNG
enum {
 HAGE,
 HOGE,
};

template<int i>
void f();

template<>
void f<HAGE>()
{
 return;
}

void f<HOGE>()
{
 return;
}

void (*func[])() = {
 f<HAGE>,
 f<HOGE>,
};

0384デフォルトの名無しさんNGNG
あ、ダメやん・・・(鬱
0385369NGNG
Modern C++ のInt2Typeとかをみてると、なーんかできそうな気がしてくるんですよねー。
どうやればいいのかはさっぱり分かりませんけど。

>>382
いや、呼び出すときは (*func[n])() ですが…。
対応させる意味がない…? えーと。考えます。
0386デフォルトの名無しさんNGNG
おいおい、じつはCOMだから関数の順序が....とかなんとか理由つけてくれよ
0387デフォルトの名無しさんNGNG
>>385
テーブルを動的に作るのはだめなん?
0388デフォルトの名無しさんNGNG
>>387
俺もそう思う。
0389369NGNG
えーとですね。ふたつの実行ファイルが、enum値に依存してるわけなんです。
エンコーダとデコーダを作ってまして。
エンコーダは、テキストの文字列 "hoge" "hage"を読み込んで、
バイナリでenum値「HOGE,HAGE」を吐きます。んで、
デコーダは、バイナリでHOGE,HAGEをみて、関数hoge(),hage()を呼ぶ、と。
そういう状況です。

>>テーブルを動的に
いや、いいんですけど。でも、静的に解決できることじゃないですか。
出来たらかっこいいじゃないですか。そういうスレじゃないですか、ここは。
0390デフォルトの名無しさんNGNG
>>389
もし出来たとしても決してかっこよくはならないと思うぞ。
0391デフォルトの名無しさんNGNG
#include <iostream>
using std::cout;
using std::endl;

enum {SAGE,MONA,MOGE,HOGE, END}; // ←ここ順番変えてよし!
typedef void (*FUNC)();
void hoge() { cout<<"hoge"<<endl; }
void moge() { cout<<"moge"<<endl; }
void mona() { cout<<"mona"<<endl; }
void sage() { cout<<"sage"<<endl; }

template<int> inline void f() {}
#define ASSOC_FUNC(E,F) template<> inline void f<E>() { F(); }
ASSOC_FUNC(HOGE,hoge)
ASSOC_FUNC(MOGE,moge)
ASSOC_FUNC(MONA,mona)
ASSOC_FUNC(SAGE,sage)
FUNC func[] = { f<0>, f<1>, f<2>, f<3> };

int main()
{
for( int i=0; i<END; ++i )
func[i]();
return 0;
}

…と思ったんだけど、関数ポインタ経由だからinline展開されないよなぁ、これ…。
0392デフォルトの名無しさんNGNG
文字列からenum値に変換するのか?
それだったら、
std::map<std::string, void(*)()> m;
m["hoge"] = hoge;
これでいいじゃん。
0393デフォルトの名無しさんNGNG
文字列->定数で解決したいんだろう

試みとしてはおもしろいかな。
でも、おれの知識じゃまだ無理だなあ。
Modern もっとよむか
0394デフォルトの名無しさんNGNG
なんかみんな無理してるよね(w
それがもの凄く伝わってくるスレ
0395デフォルトの名無しさんNGNG
>>391
改造してみた、本末転倒?

#include <iostream>
using std::cout;
using std::endl;

enum {SAGE,MONA,MOGE,HOGE, END}; // ←ここ順番変えてよし!
#define sage f<SAGE>
#define mona f<MONA>
#define moge f<MOGE>
#define hoge f<HOGE>

typedef void (*FUNC)();
template<int> void f() {}
template<> void sage(){cout<<"sage"<<endl;}
template<> void mona(){cout<<"mona"<<endl;}
template<> void moge(){cout<<"moge"<<endl;}
template<> void hoge(){cout<<"hoge"<<endl;}

FUNC func[] = { f<0>, f<1>, f<2>, f<3> };

int main()
{
for( int i=0; i<END; ++i )
func[i]();
return 0;
}
0396デフォルトの名無しさんNGNG
>>395
全然かっこよくないぞ
0397デフォルトの名無しさんNGNG
もはやかっこよさなんてどうでもいい罠
0398369NGNG
かっこよさ以前に、ちゃんと動作してくれないんですが…。VCのせい?
0399デフォルトの名無しさんNGNG
>>396
Modern(の前半)読んでかっこいいと思ったか?
俺は、すげぇとは思ったがかっこいいとは思わなかったよ(むしろ汚い)。
このスレで今やってることも同じようなもんさ。
おとなしく動的作成にしない389が悪い。
0400デフォルトの名無しさんNGNG
>>398
#include "stdafx.h"
をソースファイルの先頭に入れ忘れてるとか。
0401デフォルトの名無しさんNGNG
関数テンプレートのテンプレートパラメータに定数を使うのは、
VCだとバグのせいでうまくいかなかったはず。
たしか、すべて同一の実体を指すようになってたような。
0402デフォルトの名無しさんNGNG
そういえばそうだったな。
他のに乗り換えれ。
0403デフォルトの名無しさんNGNG
#include <iostream>

template <int i> void func()
{
 std::cout << i << std::endl;
}

int main()
{
 func<0>();
 func<1>();
 return 0;
}

これをコンパイルしてみればわかる
0404デフォルトの名無しさんNGNG
結局、VC(6以下)使ってる限りは無理って結論でよろしいか?
0405369NGNG
両方とも 1 が出力されました…。 (T_T)
0406デフォルトの名無しさんNGNG
関数テンプレートにせずに、クラステンプレートにすればいいやん。

template<int i> class func {
public:
 func() {
  std::cout << i << std::endl;
 }
};
0407デフォルトの名無しさんNGNG
すげー見にくくなってきたな・・・
0408369NGNG
たしかにクラステンプレートならVCでもいける…。
で、あとは391と組み合わせれば…?
0409369NGNG
コンパイルが通らない…。(T_T)
どうすれば…。
0410デフォルトの名無しさんNGNG
>>409
ヒント

enum {
 HAGE,
 HOGE,
};

class FuncBase {
public:
 virtual void operator()() { }
};

template<int i> class FuncObj;

template<>
class FuncObj<HAGE> : public FuncBase {
public: void operator()() {
   std::cout << "hage" << std::endl;
  }
} hage;

template<>
class FuncObj<HOGE> : public FuncBase {
public: void operator()() {
   std::cout << "hoge" << std::endl;
  }
} hoge;

FuncBase* func[] = {
 &hage,
 &hoge,
};

int main()
{
 (*func[HOGE])();
 (*func[HAGE])();
 return 0;
}

テーブルに登録するところをいじってくれ
0411デフォルトの名無しさんNGNG
正直、>>410みたいにしてまでコンパイル時に決定したいとは思わないが。
0412デフォルトの名無しさんNGNG
とりあえずなんでもかんでも関数オブジェクトにしちまうか....
最悪だな
0413デフォルトの名無しさんNGNG
はっきりいって、ここまでしてやることじゃないと思う
0414デフォルトの名無しさんNGNG
やっぱり、動的にテーブルを作るのが一番って事で、

********************** 終了 ************************
0415369NGNG
出来ました!
>>395にはかないませんけど、>>391より効率よく、なおかつVC6でも動きます。

#include <iostream>
using namespace std;

enum{HOGE,MOGE,HAGE,SAGE};// ←順番は任意に入れ替え可能
void hoge(void){cout<<"hoge"<<endl;}
void sage(void){cout<<"sage"<<endl;}
void moge(void){cout<<"moge"<<endl;}
void hage(void){cout<<"hage"<<endl;}

typedef void (*FUNC)(void);

template<int v>
struct f{
static FUNC f_;
};
#define ASSOC_FUNC(A,B) template<> FUNC f<A>::f_ = B;
ASSOC_FUNC(HOGE,hoge)
ASSOC_FUNC(HAGE,hage)
ASSOC_FUNC(SAGE,sage)
ASSOC_FUNC(MOGE,moge)
#undef ASSOC_FUNC

FUNC funcTable[4] = {f<0>::f_ ,f<1>::f_ ,f<2>::f_ ,f<3>::f_ };

int main(int argc, char* argv[])
{
for (int i=0;i<4;++i)
(funcTable[i])();
return 0;
}
0416デフォルトの名無しさんNGNG
初期状態よりも何倍も汚くなっている罠
0417デフォルトの名無しさんNGNG
まさに自己満足以外の何者でもない
0418デフォルトの名無しさんNGNG
プログラムの半分は自己満足で出来ています。
0419デフォルトの名無しさんNGNG
自己満足っつーか、ひとりよがり、って感じ。
0420369NGNG
うえーん、一生懸命考えたのに、ボロクソ言われてるよー
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄∨ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
            ∧_∧
          ( ´Д⊂ヽ
          ⊂    ノ
           人  Y
          し (_)


(´-`).。oO(っていうか、考えついたのが満足であって、>>415を使ったりはしないけどね…)
(´-`).。oO(.NETなら>>395を使えるのかしら?)
0421デフォルトの名無しさんNGNG
とりあえず、よくやった。
でも誰も使うことはないだろう。
■ このスレッドは過去ログ倉庫に格納されています