トップページ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/
0557デフォルトの名無しさんNGNG
テンプレートだけ変換することってできない?
0558デフォルトの名無しさんNGNG
>>552 が言っていることがよくわからなんだけど、
inlineとexportしてない(できない)templateとtemplateの明示的特化って
別物じゃないの?
0559デフォルトの名無しさんNGNG
ああまだ上には上がいたんだな(´Д`)
出直そう
0560552NGNG
>ちょっとした短いコード(10行以内?)以外は
>インライン実装するべきじゃない。
>デメリットのほうが大きい。
ここは一般論でその理由は>>556

>素直にテンプレートの具体的な特殊化か
>ポリモフィズムを使用するべし。
こっちは>>550に対してアドヴァイスしたつもりだった。
言葉足らずスマン。
テンプレート関数をexportできる処理系はまだ見たこと無いので
無いものとして話してる。

補足:
>テンプレートの具体的な特殊化
具体的な特殊化でテンプレート引数がすべて決まれば
普通のクラスと同じように非インライン関数として書ける。
テンプレートの用途からするとほとんど使えないテクだが・・
0561デフォルトの名無しさんNGNG
以下のようなテンプレートの特殊化がVC++(ver6)では通らないんですが
何が問題なのでしょうか?g++ならば通るんですが・・・。

template<typename T, typename U> struct test {};
template<class T> struct test<int,T> {};
0562デフォルトの名無しさんNGNG
>>561
VC++は諦めてください
0563561NGNG
マジですか?>>562
いやほんとに頼みます。
0564デフォルトの名無しさんNGNG
>>563
マジです
0565561NGNG
>>564
ありがとうございます。ショックでかいです。
で質問なんですが.NETなら大丈夫とかないですか?
スレとずれて恐縮なんですが。
0566デフォルトの名無しさんNGNG
>>565
.NETでもダメです。
正直がっかりでしたがVC8に期待しましょう。
0567561NGNG
>>566
ありがとうございました(TДT)
0568デフォルトの名無しさんNGNG
VCっていう前提が取れないところが素晴らしい
0569デフォルトの名無しさんNGNG
いまさらVC使う意味は無いと思うんだが。
0570デフォルトの名無しさんNGNG
VitaminC
0571デフォルトの名無しさんNGNG
お金が無いんだよ!!無職なんだから
0572デフォルトの名無しさんNGNG
お金がないならそれこそどうしてVC++?
0573デフォルトの名無しさんNGNG
VSのIDEでコンパイルだけgcc使えればいいのに・・・。
0574デフォルトの名無しさんNGNG
デバッグできないから意味無いじゃん
0575デフォルトの名無しさんNGNG
IDEというのはこれとなんか関係してますか?

http://www.objectcentral.com/
0576VC6に乗せたいNGNG
VS.NETが買えない貧乏人の私としては、VC6で何とか動かしてみたい。

template <class TList>
struct Length
{
  enum { value = 1 + Length<TList::Tail>::value };
};
template <> struct Length<NullType>
{
  enum { value = 0 };
};

template <class TList, unsigned int i>
struct TypeAt
{
  template<int cnt>
  struct isEnd
  {
    typedef typename TypeAt<TList::Tail, cnt-1>::Result type;
  };
  template<> struct isEnd<0>
  {
    typedef typename TList::Head type;
  };
  typedef typename isEnd<i>::type Result;
};

こういう風に書き換えればTypeListを使うことができるようになった。
既出ならスマソ
0577デフォルトの名無しさんNGNG
>>576
なんだかわからんけど、よくやった!
次もこの調子でたのむ。
0578デフォルトの名無しさんNGNG
>>576は神!!
0579デフォルトの名無しさんNGNG
>>576
よくやった!

ただ、
不明な型が厳密にひとつしかないクラステンプレートなら
部分的な特殊化を使わずに実装できるんだが
TypeListにはそうでない機能がいくつかあるんだよね。
0580デフォルトの名無しさんNGNG
VC++で無理やりSingletonHolderを動くようにしたんです。
って言ってもtemplateなstatic変数が作れないだけですから、
マクロ作って個々にインスタンスを作ってやっただけですけど。
で、ためしにLoki::SingletonWithLongevity使ってみたら
GetLongevityの戻り値が大きいほうから先に削除されちゃうんです。
ここでまたぶち切れですよ。
ModernにはGetLongevityの戻り値が小さいほうから削除されるように書かれているのに。
これはどう解釈したら言いのでしょう。
0581デフォルトの名無しさんNGNG
>>576
VC++でSelectをなんとか出来ませんか?
0582VC6に乗せたいNGNG
昼頃出先で書き込もうとしたら、串が2ch鯖に知られてて書き込めず、激しく鬱。
それはさておき。

VC++6.0は、ご承知のようにクラステンプレートの部分的な特殊化を
サポートしていません。
しかし、クラステンプレートの完全な特殊化はサポートされています。

[VC6で使えない例]
template <class TA, class TB>
struct baa{};

template <class TA>
struct baa<TA, int> ← すでに定義されているというエラーが出る
{};

[VC6で通る例]
template <class T>
struct baa{};
template <> struct baa<double> {};

あるいは、
template <class TA, class TB>
struct tee{};
template <> struct tee<double, int> {};

これだけなら大したことはできないのですが、
これをTypeAtのように、クラス内クラスで使うことで、
事実上の部分特殊化を掛けることができるようになります。

現在、手元でIndexOf まで仕上げました。
私はファンクタとダブルディスパッチを使いたいと思っているので、
それらの実装を目指すことにします。
0583デフォルトの名無しさんNGNG
>>582
おぉぉ!

template< A, B, C >

Aだけ特殊化は出来ないから
template< A > class{ template< B, C > }
にしてAを特殊化するんですね!
Select行ってみます!
0584583NGNG
Selectはできたけんども
TypeAtNonStrictで見事に撃沈・・・
完成したら作者に報告とともにどっかにウプしてくれ・・・>>583
0585583NGNG
583を訂正

template< A, B, C > struct
{
 template< A > struct
 { //↑ここを特殊化するんですね
 }
}
0586584(´д`;NGNG
584を訂正
ポインタが・・・>>583じゃ無くて>>582だ。
・・・鬱だ・・・氏んでくる
0587VC6に乗せたいNGNG
>>583殿。>>582で示したガイドラインに沿ってTypeAtNonStrictを書いてみました。

あのように作り方を明記すると、考えが整理できるものですね。
>>576で載せたテンプレートも、ガイドラインに沿った命名に書き換えました。

template <class TList, unsigned int index,
typename DefaultType = NullType>
struct TypeAtNonStrict
{
  template <class tmpTList>
  struct tmp2TypeAt
  {
    template <unsigned int cnt>
    struct tmp1TypeAt
    {
      typedef TypeAtNonStrict<tmpTList::Tail, cnt-1, DefaultType>::Result Result;
    };
    template <> struct tmp1TypeAt<0>
    {
      typedef tmpTList::Head Result;
    };
    typedef tmp1TypeAt<index>::Result Result;
  };
  template <> struct tmp2TypeAt<DefaultType>
  {
    typedef DefaultType Result;
  };
typedef tmp2TypeAt<TList>::Result Result;
};

このコードで、コンパイル、テスト動作ができることは確認しております。
願わくば、この勢いで TypeList.h で定義されている
テンプレート群をVC6仕様に書き換える作業にご協力願いたい。
正直、一人ではきついので。
0588デフォルトの名無しさんNGNG
>>587
で、今どこまで出来てるの?
協力しようにも何が出来てて何がまだなのか分からんと。

ただ、漏れ VC++ 持ってねぇんだよなぁ・・・
0589デフォルトの名無しさんNGNG
強力はおしまんですよ、TypeAtNonStrictすらできなかった漏れが役に立てるかどうかはわからんですけど、
>>587
下から6行目
> template <> struct tmp2TypeAt<DefaultType>

> template <> struct tmp2TypeAt<NullType>
だと思います。
0590VC6に乗せたいNGNG
>>588殿。恥ずかしながら、まだ IndexOf を実装しただけです。
本業もあるため、平日は遅々とした進度になるかと思われます。
できそうなところからどんどん発表していくつもりです。

あと、>>589の指摘ですが、原著の作者の実装をそのまま置き換えたため、
そのようになっております。元ソースと比較してみてください。
なお、先日から取り組んでいる Typlist 型関数は、
数値関数に置き換えれば、このようになります。

Result TypeAtNonStrict(class TList, int index,
class DefaultType = NullType)
{
if(TList != DefaultType)
{
if(index != 0)
{
return TypeAtNonStrict(TList.Tail, index-1, DefaultType);
}
else
{
return TList.Head;
}
}
else
{
return DefaultType;
}
};

元ソースよりもいくらか手続きっぽくなってるのかも。
0591デフォルトの名無しさんNGNG
age
0592VC6に乗せたいNGNG
しまった。タブの置き換えを忘れていました。スマソ

Result TypeAtNonStrict(class TList, int index,
      class DefaultType = NullType)
{
  if(TList != DefaultType)
  {
    if(index != 0)
    {
      return TypeAtNonStrict(TList.Tail, index-1, DefaultType);
    }
    else
    {
      return TList.Head;
    }
  }
  else
  {
    return DefaultType;
  }
};
0593583NGNG
とりあえず私はtypelist.hの下から行きます。
今MostDerived終わりました。後でどっかでマージしませう

あとtmpじゃ分かりにくいので名前付け方法を決めたほうがいいと思います。
私は

template <class TList, unsigned int index,
 typename DefaultType = NullType> struct TypeAtNonStrict
{
 template <class tmpTList> struct SelectTList
 {
  template <unsigned int cnt> struct SelectIndex
  {
    hogehoge...
  };
 };

 typedef SelectTList<TList>::SelectIndex<index>::Result Result;
};

のようにしました
0594デフォルトの名無しさんNGNG
す、すげー。あんたら、すげーよ。完成したら、ぜひ使わせてもらうよ! がんばってっ!
0595583NGNG
ReplaceとReplaceAll終わりました
つーか使っててすげーです、Lokiマンセー!!!
0596デフォルトの名無しさんNGNG
目から鱗すぎます。
素晴らしい。
第二版に日本人の名を連ねられるか??
期待して待つ!
0597デフォルトの名無しさんNGNG
あー
漏れ私的に使いたかったTypeTraitsの移植に挑戦してみようかな・・・
0598583NGNG
Erase以降全て終わりますた
>>597
人が作ったものは作り直したくないので、終わったらここに報告してね。
0599583NGNG
漏れがLokiと格闘してる間にイタリア1点取ってるし・・・(´д`;
0600583NGNG
うぉ!
もしかしてtypelist.h終わったじゃん。
どっかにウプしよーぜ!
0601デフォルトの名無しさんNGNG
sourceforge.comだと世界中から見つかりやすげ
0602デフォルトの名無しさんNGNG
>>601
sourceforge.netだ
0603583NGNG
>>601-602
使い方分からん・・・(´д`;

編集済みtypelist.hとtypemanip.h、
VC++用に改造したsingleton.hが入ってます。
http://www68.dns.ne.jp/~bbs2/upload3/helen/OB00011454.zip
VC++.NETで作ったので、VC++6.0で動かなかったらゴメソ

なにぶん以前は動いてなかったので、typelist.hとtypemanip.hが元と同じように動作するかは確認できてません。
特にtypemanip.hのConversionが、exists2Wayが元と違う方法を使ってるので、その辺でばぐるかも。

編集後のSingletonHolderは残念ながら元と全く同じように使うことは出来ません、
これを使うときは、
プロジェクト内のCPPファイル内でImplementLokiSingletonマクロを使って
SingletonHolderのstaticメンバ変数の実体を作ってちょ

とにかく576は間違いなく神だな・・・
神の啓示を受けた気分だ。
0604583(゚ Д ゚ ;)・・・・NGNG
もしかして・・・車輪の再発明でしたか?

http://www.geocities.com/rani_sharoni/LokiPort.html
0605VC6に乗せたいNGNG
おおおっ! ちょっと離席していた間にもう終わったのですか。すげー!
>>603は早速ダウンロードして、すべてチェックしました。
今のところ、VC6でも正常に動作しているようです。

typename とはこういうものだったのですか。
これを知らずにAppendの実装がうまくいかず、一時中断していたのですが。
知らぬではどうにもならぬですね。まだまだ修行が足りないです。
勉強になります。
0606583NGNG
LokiPortよりも漏れらのやつのほうが美しいようだ、良かった良かった。
0607583NGNG
おりょ?
やっぱりやってることはほとんど同じか・・・(鬱
(汚いと見えた)MakeTypeListやis_TypelistはLokiのバージョンアップで追加されたものかな?
0608VC6に乗せたいNGNG
>>583その「is_Typelist」が、VC6ではコンパイラに通らないです。
結局、VC6にはtypename 指定をしないと、
template<typename Head, typename Tail>
Typelist<Head, Tail>

NullType の区別がつかないようなのです。

VC.NET用はともかく、VC6用は、ここで新規開発しないといけないかも。
0609597NGNG
>>598
ダメですた。
ポインタの特殊化がどーーーしてもできまへん。
と思ったら>>604 で見事に実装されてますた。
悔しいやら嬉しいやら。

ともかく念願のTypeTraitsが手に入りますた。
ありがとうございます。
0610597NGNG
そういえばVCは
なぜか前から関数テンプレートのポインタ等の特殊化を
サポートしてるんだよな・・。
その調子でクラステンプレートも実装してホスィ
0611583NGNG
>>608
漏れはVC.NETなのでLokiPortに満足してしまいますた。
続きはがんばってください。
何かあれば協力しますし。
0612デフォルトの名無しさんNGNG
MakeTypeList age
これがあるとがぜん使う気が起きるね!
0613VC6に乗せたいNGNG
>>608まあ今時VC6でなにかしようというのが、もう時代遅れなのかもしれないですが。
>>609 LokiPort の MakeTypeList は単体で動作するようです。
>>583氏のヘッダに移植できました。

あと、うっかりサンプルソースでReverseを呼び出すのを忘れていたのですが、
こいつがエラーが出てコンパイラにとおりません。(VC6)
ガイドライン通りにちゃんと書かれているようなのですが。原因はまだ不明です。
0614デフォルトの名無しさんNGNG
このスレの前のほう見るとLokiをVCで通るようにするのは絶対無理って書かれてるな。
>>613はその発想力を大切にするといい。
0615デフォルトの名無しさんNGNG
ModernC++のページでもセンセーショナルだと書かれてるね>604
出てきたのが今年の3月だから、タッチの差は僅かだ。

MakeTypeList も上のほうで無理言われてたけどあっさり実装されちゃってる
まるで魔法だ。
C++って奥深すぎる。鬱だ。
0616デフォルトの名無しさんNGNG
テンプレート乱用しすぎますた(´д`;)
1翻訳単位のコンパイルにジャスト3分(あんまり長いので測った
まだ(やってることは)小さなプログラムなのにビルド後のファイルサイズは1MB突破・・・

テンプレート依存は一箇所に局所化して他の翻訳単位は高速化したけどそれでもつらいっす・・・
0617デフォルトの名無しさんNGNG
嘘くせー
0618616NGNG
ヽ(`Д´)ノナンダト!!
0619デフォルトの名無しさんNGNG
>>616
ひょっとしてポインタ型各種について展開してないか?
0620デフォルトの名無しさんNGNG
早速Lokiを酷使してるとか?
0621616NGNG
書き始めたころ(>>508くらい)はまだVCでLokiが動かせるとは夢にも思って無かったです。

画像の描画処理を転送・フィルター・形状・スケーリングの4つのポリシーに分けらああなりますた。
特に2つの転送ポリシーを合成するポリシーを作ったらコードサイズも時間も爆発。(まぁ当然か
0622デフォルトの名無しさんNGNG
転送をポリシーととらえるのはどうか。
ピクセルの特性をポリシーとするなら分かるが。
0623616NGNG
>>622
エフェクト、といえばよかったかも。
単純描画や飽和加算など
0624デフォルトの名無しさんNGNG
なるほど
某otakuのGTLの発展したような物ですね、
かっこよさそうです。
0625デフォルトの名無しさんNGNG
demo otaku はどこいっちゃったんでしょうか?
0626613NGNG
>>621 Effective C++で、void* で受けることで
テンプレートによって生成されるコード量を大幅に
減らすアイデアが載っていましたが、いかがか?

>>604からスレの流れが変わったので、コテハンやめるっす。

0627デフォルトの名無しさんNGNG
>>626
Effectiveもってないっす、詳細きぼん
0628デフォルトの名無しさんNGNG
STLスレって倉庫落ち?
0629デフォルトの名無しさんNGNG
>>628
ageたよ
http://pc.2ch.net/test/read.cgi/tech/1004287394/
0630デフォルトの名無しさんNGNG
あぐ
http://pc.2ch.net/test/read.cgi/tech/1021787032/556
に書いてしまった…。サンクスコ>>629
0631613NGNG
>>627
Modern C++ Designは Effective C++に書いてあることが前提になっているので、
先に読んでおいたほうがいいですぞ。買っても後悔しないです。

要は、コンテナに入れるものをvoid*として格納するコンテナを用意しておき、
要素に対する操作を定義しておきます。(ソートだとか何とか)
で、void*として放り込む作成・破壊クラスを別に定義します。
確かこんな感じだったはず。詳細は当該書籍を読まれよ。
0632デフォルトの名無しさんNGNG
既出の質問かもしれませんが、教えて下さい。
メンバー関数の有無によってコードを書き分けるにはどうしたら良いのでしょうか。

例えば、次のようなテンプレートクラスがあるとします。
template <class A>
class X {
 void func() {
  if (/* A::foo() があるかどうかの判定*/) }
   /*CODE1: A::foo()を使う処理 */
  } else {
   /*CODE2: A::foo()を使わない処理、もしくはA::foo()の処理を肩代りする処理*/
  }
 }
};

ここでクラスA1にはメンバー関数foo()があり、
クラスA2にはメンバー関数foo()がないとします。

このとき、X<A1>::func()とX<A2>::func()は
それぞれCODE1とCODE2の部分だけ実行するようにしたいのです。
できれば、判定をコンパイル時に行ない、コンパイルされたオブジェクト
にはコードが最適化されてCODE1とCODE2のどちらかしかしか
存在しないようにしたいと思っています。

こういうことは可能でしょうか?
可能だとするとどのようにしたら良いでしょうか?
0633デフォルトの名無しさんNGNG
>>632
タグディスパッチ
0634632NGNG
>>633
さっそくどうもありがとうございました。

Googleで検索してみたら、次のURLがヒットしました。
http://www.issei.org/programming/boost/more/generic_programming.htm
ここで言われているのがそれですか?

なかなか凝ったやり方に感じましたが、勉強になりました。
0635デフォルトの名無しさんNGNG
>>632
C++にはリフレクション機能が無いので
特定メンバあるかどうかの判断はできない。(・・よね?)
だから他の条件が必要。

渡されるクラス全てにタグを定義とかの制限をつけてもよいならタグディスパッチ
だめならlokiのTypeTraitsで使えそうな特性をみつけるとか。
私的には特定のクラスのサブクラスかどうかで分けるのが良いと思うが。
0636626NGNG
>>613 なんだかよく分からないのですが、
>>583氏のヘッダに適宜 LokiPortのコードを移植することで、
LokiPortのTest_Typelist.cpp がコンパイルできてしまいました。
ということは、Typelistに関してはVC6でも動作可能ということですよね。
ううむ。

0637デフォルトの名無しさんNGNG
移植完了品をパッチかアーカイブの形式で全部UPしてください
0638デフォルトの名無しさんNGNG
>>636
VC6ってテンプレートパラーメータサポートしてなかったと思うけど
どうやってるの?
0639デフォルトの名無しさんNGNG
>>638
ん? できないのは部分特殊化でしょ?
テンプレートパラメータサポートしてないってどういうこと?
文字通り取るとtemplate自体使えないような。
0640デフォルトの名無しさんNGNG
>>639
テンプレートテンプレートパラメータのことでしょ。わざわざ揚げ足取らんでも。
template< class A, template<class> B > class C { ... };

ってゆーかしかし、LokiのTypeListって部分特殊化さえあれば動くと思ったが。
0641デフォルトの名無しさんNGNG
>>640
どういうときに使うの?
0642デフォルトの名無しさんNGNG
>>641
http://www.comeaucomputing.com/techtalk/templates/#ttp
0643デフォルトの名無しさんNGNG
LokiPortのTypeTraits::isConstがうまく動かない・・
参照型が問答無用でconstと判断されてしまう。
まぁあんまり使い道の無い機能ではあるが
ザンネン。
0644デフォルトの名無しさんNGNG
・・・よくよく考えると
参照そのものは変更できないからconstという判断でいいのかな。
そういうことにしよう!
0645デフォルトの名無しさんNGNG
ん?
isPointerの実装おかしいような??
これconstの判別できないだろ?
0646デフォルトの名無しさんNGNG
>>644-645
仮にVC++の話であるなら
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrf14552partialorderingoffunctiontemplates.asp
なのでそこんとこ注意。
0647デフォルトの名無しさんNGNG
>>646
そうなんだよね・・
それなのになんで動くのかちと不思議。
保障されない動作なんだろうか。

とりあえずisPointerはポイント先の修飾された奴を全部消して
コンストポインタの判定を追加したらうまく動いた。
0648デフォルトの名無しさんNGNG
template<typename U>
static yes is_pointer1(Type2Type<U *>);
static no is_pointer1(...);
template<typename U>
static yes is_pointer2(Type2Type<U * const>);
static no is_pointer2(...);

enum {
isPointer =
sizeof(is_pointer1(Type2Type<T>())) == sizeof(yes) ||
sizeof(is_pointer2(Type2Type<T>())) == sizeof(yes) ||
};

これで動いた。
これって単に動作確認してなかったのかな。
それともSPあてる・あてないで動作変わったのかな・・
0649デフォルトの名無しさんNGNG
>>632
激しく遅レスだが
VC++には__if_exists/__if_not_existsなるキーワードがあって
関数や変数の有無で処理を分けられる
移植性を考えれば使えないが
0650デフォルトの名無しさんNGNG
>>649
それどうやって使うの?
解説キボンヌ
0651デフォルトの名無しさんNGNG
>>649
それって.NET専用?
0652デフォルトの名無しさんNGNG
>>650

#include <iostream>

int main(void)
{
int a;
__if_exists( a ){ std::cout << "a ハケーン" << std::endl; }
__if_not_exists( a ){ std::cout << "そんな変数無いです" << std::endl; }
}

こんな感じ
このままだと "a ハケーン" が表示される
int a;をコメントアウトすると "そんな変数無いです" が表示される

( ) 括弧の中は変数だけじゃなくて、任意のシンボルが入れられる。
もちろんメンバ関数も。
0653デフォルトの名無しさんNGNG
>>651
ネイティブにも使えるけど、もしかしたらVC++.NETから新しく追加された機能かも
0654デフォルトの名無しさんNGNG
6.0には無かった。
0655名無しさんNGNG
>>649
メンバー、メソッドでもOKなの?
0656デフォルトの名無しさんNGNG
このスレに巣食ってる型はハイレベルですね・・・。
■ このスレッドは過去ログ倉庫に格納されています