トップページ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/
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
このスレに巣食ってる型はハイレベルですね・・・。
0657デフォルトの名無しさんNGNG
こういうのぜひ 規格 にフィードバックして欲しい
(識別子をどうするかは、考えないといけないが)
0658デフォルトの名無しさんNGNG
>>657
コンパイラによるリフレクション? 規格はさすがに無理ぽそうだけど...
0659名無しさんNGNG
つーか、どういう時に効くのかな?
ウヒャ─、これは便利、って例ある?

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrfthe__if_existsstatement.asp
memberもOKなのね。しかし、なんじゃこりゃ? って感じ。
0660デフォルトの名無しさんNGNG
std::advanceのようなアルゴリズムを記述するのに、
タグディスパッチがいらなくなるんじゃない
0661名無しさんNGNG
template <class _Iterator, class _Distance>
inline void advance(_Iterator& __i, _Distance __n) {
 __if_exists( _Iterator::operator[]){ __i += __n; } // random
 __if_exists( _Iterator::operator--){ if (__n >= 0) while (__n--) ++__i; else while (__n++) --__i; } // bi
 // elseがないからtag抜きでforward iterator書きにくい。
}
こんな感じ?


 
0662デフォルトの名無しさんNGNG
Templateを初心者にも分かりやすく教えてください。
0663デフォルトの名無しさんNGNG
>>662
コンパイラがコンパイルの前に置換をしてくれるんだよ。
プリプロセッサがやる単純な置換と違い、コンパイラが型チェックに
責任を持ってくれる。

0664デフォルトの名無しさんNGNG
>>633
Templateはどういうときに使うのですか?
0665デフォルトの名無しさんNGNG
>>664
リストって知ってるよね?単方向でも双方向でも。

例えば、構造体Aと言う値を保持するリストのクラスを作ったとする。
これがなかなか便利で他のプログラムにも使いたい。

しかし、構造体Aは前のプログラム独自の物なので汎用性を持たせたい。
そこで、構造体Aの代わりにvoid *を持たせることにした。

しかし、これでは型キャストの嵐になるし、新しいノードを作るとき、自動的にデータ格納用の
メモリ領域を確保したり開放したりすることが困難になる。

next = new nextnode();
next.data = new ここを使う型が変わるたびに変更しなくてはならない。


そこでテンプレート。これは特定の抽象型を具体的な型に置換できる。
例えば、データ用の型をDATAとし、それをintと具体化すれば、
int型を扱うリストが出来るし、struct aaaと具体化すればaaa構造体のリストとなる。
0666デフォルトの名無しさんNGNG
あれ、完全に置換はしないってあったような気がするけど
0667デフォルトの名無しさんNGNG
>>664
抽象化する時
(メソッドとか関数とか)
0668613NGNG
>>663 >>665

激しくスレ違いに真面目にレス。2ちゃんねらーの鑑です。
私も見習わないと。

ということで真面目レスを追加しておきますと、
テンプレート(template)の萌芽はMFCのコンテナにも見られます。
(CMap、CListなど)

でもやはり、STLは一通り勉強しましょう。
ttp://www.wakhok.ac.jp/~sumi/stl/index.html
それから、Effective C++、More Effective C++を一通り読んで、
>>1 のModern C++ Design を買えば、
晴れてこのスレの住人に仲間入りです。
頑張りなされ。
0669デフォルトの名無しさんNGNG
Effective C++、More Effective C++、Modern C++ Design
いくらかかると思ってんのYO(`Д´)
0670デフォルトの名無しさんNGNG
>>669
全部持ってるYO!高かったけど仕方ないYO!
0671デフォルトの名無しさんNGNG
>>669
書籍にかけた金は、すぐに仕事実績で取り返せる(ちゃんと読めば)。惜しむな。
0672デフォルトの名無しさんNGNG
> 書籍にかけた金は、すぐに仕事実績で取り返せる(ちゃんと読めば)。惜しむな。
そう思いこみたいんですね :)
0673デフォルトの名無しさんNGNG
>>672
怖がりすぎー。
0674デフォルトの名無しさんNGNG
「primitiveな変数をいちいちconstructorで
初期化するのはめんどくせー」ってことで、
WithInit< int , 600 > m_intvalue;
ちゅーよーなのを書いた。
ひょっとして、車輪を再発名した……?
0675 ◆4COMPILE NGNG
>>674
勝手に600に初期化されるint ってこと?
0676ageNGNG
VC++.NETにて下記のコードで InnerInStrict がコンパイルエラー
"error C2516: 'Inner' : は正しい基本クラスではありません。"
を吐きます。
InnerInFunc は問題なく通ります。
これはC++の仕様?それともVC++の問題?
InnerInStruct も使えるように出来ないのでしょうか?

struct Base{ struct Inner{};};
template< typename T > struct Mid: public T{};

template< typename T > struct Sub
{
 struct InnerInStruct: public Mid< T >::Inner{};
 Sub()
 {
  struct InnerInFunc: public Mid< T >::Inner{};
 }
};

int main(void)
{
 Sub< Base > sub;
}

0677デフォルトの名無しさんNGNG
>>674
整数型でしか使えないじゃん。
0678デフォルトの名無しさんNGNG
>>676
g++3.1やbcc5.5.1では何ごともなく通ったよん
0679676NGNG
>>678
鬱・・・
0680デフォルトの名無しさんNGNG
>677
bool, int ,char , short, long , float, doubleと使えれば
充分じゃねーんすか?
0681デフォルトの名無しさんNGNG
Genericプログラミングマニアのみなさま。汎用シーケンスコンテナを作れませんか。

Effective STLの第2項、「コンテナに依存しないコードという幻想に注意しよう」を
読んだ上で言ってます。
vector,deque,listってのは、しょせん実装の詳細なわけですから、最初っから
「汎用シーケンスコンテナ」ってのがあって、その実装を、vector,deque,listなどの中から
ポリシーで選べたら便利なんじゃないかと思うわけですが。
Effective STLには、たとえば「vectorをサポートしようとすると、push_frontとpop_frontを
使用できない」とか書いてあります。要するに、「全部に共通するメンバ関数がないから、無理」
ってなことに過ぎないわけでして。全部ラップして作り直せば問題解決なんでは、と思った
わけです。どうでしょう?

// ポリシークラスその1。vectorによる実装。
template<class T>
class ImplVector
{
public:
  typedef std::vector<T> cont_t;
  typedef cont_t::iterator Iter;
  typedef cont_t::size_type SizeType;
private:
  cont_t c_;
public:
  void PushFront(T val){
    c_.insert(c_.begin(),T);
  }
  void PushBack(T val){
    c_.push_back(T);
  }
  void Erase(T val){
    // eraseとremoveの慣用的用法ってやつ。
    c_.erase(remove(c_.begin(),c_.end(),val),c_.end());
  }
  T& operator[](SizeType n){
    return c_[n];
  }
};
0682681NGNG
// ポリシークラスその2。listによる実装。
template<class T>
class ImplList
{
public:
  typedef std::list<T> cont_t;
  typedef cont_t::iterator Iter;
  typedef cont_t::size_type SizeType;
private:
  cont_t c_;
public:
  void PushFront(T val){
    c_.push_front(T);
  }
  void PushBack(T val){
    c_.push_back(T);
  }
  void Erase(T val){
    c_.remove(T);
  }
  T& operator[](SizeType n){
    Iter it = c_.begin();
    for (int i=0;i<n;++i){
      ++it;
    }
    return *it;
  }
}

// Generic Sequence Container
template
  <
    class T,
    template <class> class ImplContainer = ImplVector
  >
class GSC : public ImplContainer<T>
{
};

GSC<int> gsc;
gsc.PushBack(3);
gsc.PushFront(5);
gsc.Erase(3);
int a = gsc[0];

こんな感じで、効率の良し悪しは無視して、思いつく限りのメンバ関数を
用意しておけばいいんじゃないかなと。後で「vector実装でOKだと思ってたけど、
list実装の方がよかったな〜」ってときは、GSC<int>って定義をGSC<int,ImplList>に
変えるだけです。使ってる部分のコードは全く変更しなくていい、ってのが当然の目標。

……とかいって、どっかですでに開発されてましたー、じゃ虚しいんで、
存在を知ってる人がいたら、さっさとツッコミ入れてくださいね。
0683デフォルトの名無しさんNGNG
>>674
初期値を変更したくなったときに依存してるソース全部で
再婚パイルが必要なのって面倒い。

>>682
「vectorでOKだと思って operator[] を使って色々実装していたけど
やっぱりlistの方が良かったなー」なんてことは起こり得んと思うがどうか。

例えば std::queue のコンテナにはほとんどの実装だと list/deque は取れても
vectorは使えないけれど、それはvectorを使う意味が全くないからであって、
そこにあえてvectorを渡せるように汎用性を持たせる…みたいなことって
やってもしょうがないのでは。
0684デフォルトの名無しさんNGNG
>>680
> bool, int ,char , short, long , float, doubleと使えれば
> 充分じゃねーんすか?

いや、template に float や double (char もか?) の即値はつっこめないのではないかと。。。
0685681NGNG
>>683
いや、それは単にそういうありえなさそうな状況を挙げてるだけでは。(^^;
operator[]を使うって事は最初っからlistが考慮の外なのは明らかですから、
そういう状況を持ってきて否定されても。std::queueのほうも、目的が
はっきりしているなら、汎用シーケンスコンテナなんて必要ないのは
あたりまえです。

とりあえず、俺がこれを欲しいと思った動機を。vectorでもlistでもいいような、
曖昧な状況で『とりあえずvector』で開発をはじめたけど、あとで『げ、中間への
データ挿入が出てきた。やっぱlist』って切り替えたくなったんです。そのとき、
データ削除部分の形がvectorとlistでは全然違うやん、ってので参ったんです。

要するに、『どのシーケンスコンテナが最適なのか、不透明な状況』に対して
最適な回答をもたらすために、汎用シーケンスコンテナがあればいいなぁ、と。

どのコンテナが最適なのかわかんないうちから開発を始めてんじゃねーぞ、
って言われたら、「はい、ごめんなさい」と凹むしかないですが……。
0686デフォルトの名無しさんNGNG
Effective STLに書いてあったかどうかしらんが、必ずtypedefをするようにしとくだけで
いいんでないの?

いちおう、
どういうコンテナを使うべきかの分析無しで作りはじめてんじゃねーゾ。
0687デフォルトの名無しさんNGNG
age
0688668NGNG
>>685
私の場合は、テキストエディタを作るときに1行のテキストを
stringに入れて、listに入れて使いました。
stringはコピーにコストがかかるので、

vector::[] + insert よりは、
list::advance + insert の方がパフォーマンスがよかったです。
(advance 10万回で0.04秒程度)

しかしそれはコンテナの性質と設計上の要請を勘案すれば
事前に分かることで、わざわざポリシーにするほどのことではないと思うのですが。
0689デフォルトの名無しさんNGNG
テキストエディタはlist+キャッシュと言うのが常套手段だよな。
もう常識中の常識。

それより、1行に持てるデータの構造をどう記述するかの方が問題。
0690681NGNG
>>686
typedefは必ずやってます。>>681で書いてるみたいなやつを。
でも、typedefじゃ『削除』はどうにもならないんですよね。

とりあえず逝ってきます……。
0691デフォルトの名無しさんNGNG
listっておい、まともなやつはgapped bufferだろ..
0692デフォルトの名無しさんNGNG
>>691
listとギャップバッファは用途違うと思うが?
それから、ギャップバッファも1行に保持するデータが長くなってくると
パフォーマンスががた落ちするよ、所詮2セグメントのデータだからね。
0693デフォルトの名無しさんNGNG
>684
VC++6で、double即値、char即値ともつっこめますた。
0694648NGNG
Boostにごっついtype_traitsの実装があることに今ごろ気付きますた・・・!!
死のう。
0695デフォルトの名無しさんNGNG
>>691は何行になるかわからんのにいちいち行ごとに
オブジェクト作るなって言いたいんじゃないのか?

そういう点でみれば>>692のは激しく的はずれ

0696デフォルトの名無しさんNGNG
gapped bufferってn行へジャンプとかが苦手じゃないの?
0697デフォルトの名無しさんNGNG
苦手といえば苦手だが克服は簡単だよ
最近のPCは速いし。
0698デフォルトの名無しさんNGNG
listと違ってn行へのジャンプが定数時間で終わるのがgapbufferじゃないのか?
0699デフォルトの名無しさんNGNG
>>698
gapped buffer って、バッファの内容をカーソル位置で分割して管理する方法だよね。
それだと、コストはこうじゃないかな。

gapped buffer
 一文字追加、削除 O(1)
 指定行の移動 O(バッファの総文字数)

リスト
 一文字追加、削除 O(一行の文字数)
 指定行への移動 O(ファイルの行数)

gapped buffer は「普段よく使うのは一文字単位の追加・削除だから、こっちを
早くしたほうが快適だ」という信念に基づくデータ構造だと思うよ。ついでに、今
時の PC を前提とするなら、どっちでも早すぎて変わらん。
0700デフォルトの名無しさんNGNG
>gapped buffer って、バッファの内容をカーソル位置で分割して管理する方法だよね。

これだと先頭から終端までジャンプするのに、バッファのコピーが発生するよね?
めちゃくちゃ遅くならない?
0701デフォルトの名無しさんNGNG
>>700
挿入・削除のタイミングでバッファ内の整理をすればよいので
全然そんなことない。

極端にでかいファイルもストレスなく開けるようにするのに便利。
0702デフォルトの名無しさんNGNG
VZは行編集バッファを別に持って、
何か書き換え始めたら行編集バッファにコピーしてきて編集し、
カーソルがその行から出たりするタイミングで書き戻してたっけ。
0703デフォルトの名無しさんNGNG
ちょっと質問 gapped bufferってデータを
head part  cursor    tail part
|-----------| + |------------|
こんな感じで持つ構造と考えて良いのでしょうか?

それとも、下の様にいくつかのフラグメントに分けて保存して、
編集時のコピー量を少なく納める構造なのでしょうか?
|-----| |-----| |----+-| |------|

日本語のサイトをいくつか検索しても、
どっちとも取れるようなどっちも違うような記述でよく分かりません
0704名無しさんNGNG
後者は変形の一つ。

>>700
正直、editorならほとんど変りがない。今や一番重いのはGUIの描画。
0705デフォルトの名無しさんNGNG
>>703
カーソル位置とギャップ位置は関係ない
ギャップは普通エディットしている部分に作られる
0706デフォルトの名無しさんNGNG
どうでもいいけど話題がスレ違い
0707デフォルトの名無しさんNGNG
ではだれかgapped bufferをgenericに実装した例をキボンヌ
0708デフォルトの名無しさんNGNG
>>707
http://www.google.co.jp/search?sourceid=navclient&hl=ja&ie=utf8&oe=utf8&q=%E3%82%AE%E3%83%A3%E3%83%83%E3%83%97%E3%83%90%E3%83%83%E3%83%95%E3%82%A1
0709デフォルトの名無しさんNGNG
gapped bufferのメリットがぜんぜんわからぬ・・・
0710デフォルトの名無しさんNGNG
http://www.jah.ne.jp/~naoyuki/Programs/Programs.html
ここにあるな
0711デフォルトの名無しさんNGNG
STLPortとLokiPort(のSmallObj)同時に使えないっすね。
STLPortのlower_boundに不具合があるんですけど、
どうにもならないですかね。
0712デフォルトの名無しさんNGNG
>>711
lower_boundにどんな不具合がありますか?
0713デフォルトの名無しさんNGNG
>>712
ぉ!
Generic Programing and the STL見てみたら、
STLPortの動作のほうが正しいですね。
// MSDNには書いてない新たな条件が・・・
LokiPortのほうの使い方に問題があるみたいですね
0714デフォルトの名無しさんNGNG
boostのTypeTraitsのコード読んでたんだが
ちょっと前、Lokiの移植で話題になってたVCで
テンプレートの部分的な特殊化をエミュレーションしてる部分に
こんなコメントかいてあるんだけどあれのどこが not legal なの?
ーー以下引用ーーー

// the following VC6 specific implementation is *NOT* legal
// C++, but has the advantage that it works for incomplete
template<class T1>
struct is_same_part_1 {
template<class T2> struct part_2 { enum { value = false }; };
template<> struct part_2<T1> { enum { value = true }; };
};

ーー引用ココまでーー
他のコンパイラでは動かないのかな?
0715デフォルトの名無しさんNGNG
.NET Framework SDKについてるC++のコマンドラインコンパイラでは
Lokiを使えますか?
0716デフォルトの名無しさんNGNG
>>715
過去ログよめ
0717デフォルトの名無しさんNGNG
>>716
過去ログにはVC++.NETとあるだけなので、VisualStudioなのか
.NET Framework SDKだけでも大丈夫なのかわかりませんが。
0718デフォルトの名無しさんNGNG
>>717
一応、最適化のオプションが使えなくなってるだけで、
あとは普通にManagedも吐ければ、通常コンパイルもできる

まずは使ってから質問しろ。
lokiが使いたいだけならgccにしろ。
0719デフォルトの名無しさんNGNG
>>718
使うかどうかまだ決めてないんで。
情報どうも。
0720デフォルトの名無しさんNGNG
>>719
LokiPortを使えば?
http://www.geocities.com/rani_sharoni/LokiPort.html
0721デフォルトの名無しさんNGNG
VC7.0のコンパイラって何処で落とせますか??
0722デフォルトの名無しさんNGNG
>>721
http://msdn.microsoft.com/netframework/
0723デフォルトの名無しさん NGNG
VC7.0はtypeof演算子は使える?
g++だといけるんだけど。
0724デフォルトの名無しさんNGNG
>>723
それがGeneric Programmingと何の以下略
0725デフォルトの名無しさんNGNG
>>724
コンパイラへのプログラミングにおいて
限られた道具が増えることは、かなり重要なことだと思うけど・・・

今のところ、どう使うか考えてるところではあるんだけどね:)
0726デフォルトの名無しさんNGNG
処理系依存の話は、できれば余所でお願いしたいところだが。

(まぁ C++ の template 自体、完全実装してる処理系はほとんどないから、
処理系依存に近いのが現状だけどさ)
0727デフォルトの名無しさんNGNG
http://www-cdserver.fnal.gov/cd_public/sag/J16/J16.htm
http://www-cdserver.fnal.gov/cd_public/sag/J16/J16_files/slide0042.htm

• typedef templates:
template< class T >
typedef std::map< std::string, T > Dictionary;
Dictionary<double> d;
Dictionary<PhoneNumber> phonebook;

• typeof() compile-time operator:
template< class T >
void foo( T t ) {
  typeof( f(t) ) y = f(t);
… ;
}

こりゃ凄いと思うがどうよ。
0728デフォルトの名無しさんNGNG
あ、凄いのはtypedef templateの方ね(笑
0729デフォルトの名無しさんNGNG
どっちもホスィ・・・
0730デフォルトの名無しさんNGNG
typeofって拡張だろ?
0731デフォルトの名無しさんNGNG
>>730
標準に含めて欲しいっていう提案はされてるみたい
0732デフォルトの名無しさんNGNG
なるほど、スレ違いってうまい言葉だなあ
0733標準化委員会NGNG
typeofはもうすぐ導入予定です
0734デフォルトの名無しさんNGNG
typeofはいいから早くANSIに対応してくれよ>VC++

g++ってあれだけがんばってるのに、ユーザーは
相変わらずCでゴリゴリ書くのが好きな人ばっかりで、
なんか哀れだよね。
0735デフォルトの名無しさんNGNG
typeof萌え、標準にすぐ入れるべし、
0736デフォルトの名無しさんNGNG
typeofはテンプレートのないCに取り入れられた方が
劇的にコーディングスタイルが変わりそう。
0737デフォルトの名無しさんNGNG
>>736
マクロプログラミングですか?
イヤだなぁ
0738デフォルトの名無しさんNGNG

#define foreach( itr, cont ) for( typeof( (cont).begin() ) itr = (cont).begin(); itr!=(cont).end(); ++itr )
0739デフォルトの名無しさんNGNG
template<typename T>struct SA{
   template<typename A,typename B>struct TSA{TSA(){cout<<"A"<<endl;}};
   template<>struct TSA<T,int>{TSA<T,int>(){cout<<"B"<<endl;}};
   template<>struct TSA<T,double>{TSA(){cout<<"C"<<endl;}};←これが警告になって、しかも無視されるのがわからない。なんで?
};
0740名無しさん@カラアゲうまうまNGNG
オーバーロードの曖昧さ?
0741デフォルトの名無しさんNGNG
Cスタイルの文字列を受け取れるテンプレートで、
const char* を受け取れるようにしとけば動作するけど、
template< unsigned N > f( const char (&x)[N] );
にバージョンを用意しとけば、文字列リテラルを受け取ったときに、
N で文字列長を受け取れる分、より効率的に処理できるようです。
ですが、↑みたいなテンプレートを使ってるのをほかで見たことがありません。
なにか問題があるからなのでしょうか?
それとも、見つけれて無いだけで、めずらしくもない方法なんでしょうか?
0742デフォルトの名無しさんNGNG
>>741
boos::type_traits::is_array
0743デフォルトの名無しさんNGNG
^boos^boost
0744741NGNG
>>742
配列型の判別はできても、boostのやつには N が取れないように見えますが、
同じことができるってことですか?
0745デフォルトの名無しさんNGNG
LokiPortのis_arrayにも似たような記述があるが
環境依存な部分も少なからずあるみたい。
ただ単にサイズを自動的に取得したいという目的ならば不要かと。
const char* との共存ができないようだし。(VC7)
普通にstring(literal, sizeof(literal))で問題無いかと。
0746デフォルトの名無しさんNGNG
もうtemplateは疲れた。
0747デフォルトの名無しさんNGNG
正直、Lokiの延長みたいのが仕事で使われるようになったら、
この業界辞める。もっとらくちんなの希望。
0748デフォルトの名無しさんNGNG
>>747
ライブラリ作るのとそれ使うのとでは全然違うと思われ
0749デフォルトの名無しさんNGNG
>>747
激しく同意。
STLのように使うだけのライブラリとはちょっと違う。
プログラム設計において根本から変わってしまうような
ものだと思う。
というかそろそろ言語の機能をフル活用しなければならない
っていう呪縛から逃れたいところだね。C++使ってるひとには
自分も含めて、この傾向が強いから。
0750デフォルトの名無しさんNGNG
自分が便利だと思う機能をしっかりと使えればいーんじゃネーノ?


……と思ったが、そうすると他人のプログラムの保守ができんな。
0751デフォルトの名無しさんNGNG
機能は、必要を感じた時に初めてその使用の検討をするべき。
templateなんて特にそうだと思うぞ。
俺は無いと困るみたいな状況に陥ったことがないので、
使ったことは無いが。w
■ このスレッドは過去ログ倉庫に格納されています