トップページ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/
0002デフォルトの名無しさんNGNG
じぇねりっく
0003デフォルトの名無しさんNGNG
とりあえずネタふり。

1で挙げた Modern… は、3章まで読んだ。いままでのところ、ムズいと
感じたのは 1章かな。ポリシーというのになじみがなかったもので。
正直、ポリシーと特性 (traits) の違いがよくわかっていない。

3章はテクニックの話なので、むしろ分かりやすかった。LISP という
よりは prolog とかの単一化のイメージに近いね。こんなことが
template でできるということには驚いたが。でも、タイプリスト
なるものの使い方については、まだ、まったくわからん。
0004デフォルトの名無しさんNGNG
何ができるのか具体的に書いてくれよ。
0005デフォルトの名無しさんNGNG
一個のタイプミスで百行ぐらいエラーを出せる。
0006デフォルトの名無しさんNGNG
>>3
> でも、タイプリストなるものの使い方については、まだ、まったくわからん。
型によってコンパイル時に関数を選択させる場合に使える。STL で似たようなことをやってるのは、
iterator によってアルゴリズムを選択してるヤツかな。たとえば advance() は

  randome access iterator なら iter += n
  forward iterator なら ++iter を n 回

で処理するようになってる。(あれの魔法の種は iterator_traits なんで、ちょっと違うけど)
0007デフォルトの名無しさんNGNG
具体例: 1の本の「推薦の言葉」から。

// コンパイル時にチェックできる assert
template<bool> struct CTAssert;
template<> struct CTAssert<true> {};

で、たとえば CTAssert<sizeof(int) == 0> とかやるとコンパイルエラーを
出してくれる。ぜんぜん generic ってな感じはしないけどね。
0008デフォルトの名無しさんNGNG
STLスレでやれよ。
0009デフォルトの名無しさんNGNG
>>8
意味わかってる?
Generic Programingとは違う。
この本に載っている技法は「Generative Programming」生成的プログラミング
といわれるだぜ?

俺は「Generative Programming」萌えだ。
C++のtemplate特性を逆手に、とった巧妙な技法だ

ちなみにC++に依存してるわけじゃない。
たぶんPerlでもASPでもできる。
0010デフォルトの名無しさんNGNG
漏れも Modern ... 読んでる YO!
楽しい NE!

デモチョトボクニハムズカシイヨ…
0011高校生NGNG
いったいどういうものなんですかね?>Generative Programming
いわゆるGoFのPrototypeパターンとは別物?
それともLISPのマクロみたいに実行時にクラスを
生成するのか?(C++では絶対無理だと思うが。。。)

#例外が実装される前は良く使ったけどなぁ>C++
0012デフォルトの名無しさんNGNG
>>11
>それともLISPのマクロみたいに実行時にクラスを
>生成するのか?(C++では絶対無理だと思うが。。。)

もちろんLISPのようなクラスを生成というのは無理だ。
ある意味、LISPの様にC++でも生成できる様にしている。
templateを使いクラスを生成するためパーツを作ってるんだ。
0013高校生NGNG
なんか面白そうだなぁ。。。GoFの23パターンとは
違う新手のアーキテクチャーなんだろうか?
訳書で4800円か。。。まずは立ち読みから(;;
001412NGNG
上のものは誤解を招きそうなので補足する。
(まあ俺は消防だから話半分ぐらいで聞いてくれ)

Generative Programmingとオブジェクト指向は直行している
Generative ProgrammingとSTLを使うとHaskell的プログラミングができそうだ。

「Modern C++ Design」のHP
ttp://cseng.aw.com/book/0,,0201704315,00.html
にLokiといライブラリが公開されている。
見てみてはどうかな?
(サンプルコードが無いから本を読まないと使えんか)
0015デフォルトの名無しさんNGNG
>>11
Generative じゃなくて Generic の方だが、俺は次のように理解している。

手続き型のプログラミングでは「手続き」を定義することで、
オブジェクト指向プログラミングでは「インターフェース」を定義することで、
ソフトウェアの抽象化を進めた。

それでも抽象化できてないものの一つに「ループ」なんてのがある。たとえば整数の配列や
文字列をコピーするコードは、効率を考えなければどれも

for (i = 最初; i < 最後; ++i)
  dst[i] = src[i];
みたいなものだが、これは手続き型でも OO でも、汎用的には書けないわけだ。コピーする
「手続き」、たとえば memcpy とかあるだろと反論するかもしれないが、あれは

 特定の型やデータ構造に縛られる

という点で、汎用的ではない。たとえば C++ のオブジェクトなんかは、単純にメモリをコピー
して済ますわけには行かない。参照カウンタつきのクラスなんかは、そんなことしたら確実
に壊れるし。

そこで「一連の要件」を定義することで、汎用的で再利用可能なアルゴリズムを定義できる
ようにしたのが Generic プログラミング(C++ の規格書読んでると Assinable Type とか出
てくるけど、あれが要件)。ただ「一連の要件」というのが曲者で、手続きや型と比べると把
握しづらいんだよな。

C++ でうまくテンプレートを使ったコードを読むと「このループ何」みたいなことが少ない。
ループや比較に名前がついていて、コードを読んで意図が汲みやすいようになってる。
いまどき変数を使わずアドレス直書きなプログラムなんざ

 「たとえ正しく動いていようが、こんなプログラムメンテナンスできん」

と思うように、将来は名前の無いループや比較演算を直接埋めたプログラムは

 「読めるか、こんな抽象度の低いコード」

とか言われるのかも知れず。
0016デフォルトの名無しさんNGNG
直行ってなんですかー?
0017デフォルトの名無しさんNGNG
情報提供:三省堂
■[直行]の大辞林第二版からの検索結果 

ちょっこう ちよくかう 【直行】

(名)スル

(1)途中どこにも寄らず、目的地へまっすぐ行くこと。「出張先から会社に―する」
(2)人の思惑などを考えず思うとおりに行うこと。「直言―」「―の士」
(3)正しいおこない。
0018デフォルトの名無しさんNGNG
>>16
まじれす
各概念が独立していること
単独でも使えるし、組み合わせることも可

(元ねた、XYグラフはX軸とY軸は直行している)
0019高校生NGNG
>>15
一種のTemplate methodと考えるのはまずいですかね?
>>18
一次結合のヴェクトルが一次独立なら「直交」が正しいと思う。
0020デフォルトの名無しさんNGNG
>>18
ちゃいます。
正直、ム・マ板では「直交」はNGワードですな(藁

>>19
正解(漢字が)
0021デフォルトの名無しさんNGNG
>>19
> 一種のTemplate methodと考えるのはまずいですかね?
それはあくまで「手法」の一つであって、背景にある「概念」とは異なると思う。オブジェクト指向って
関数ポインタですよね、というのと同じぐらいには外してると思うぞ。

(Generic プログラミングをサポートするのは C++ に限らないわけだし)
0022デフォルトの名無しさんNGNG
age
0023デフォルトの名無しさんNGNG
Builderつかってるんだけど、
テンプレート使ってると時々コンパイラがFatalErrorを吐く。
自分が間違っているのか、コンパイラの問題なのか分からなくて悩む。
ま、VC6よりはましだけど。

#とりあえずage
0024デフォルトの名無しさんNGNG
>>23
Templateだけ展開するコマンド無かったっけ?
0025デフォルトの名無しさんNGNG
>>23
どんなコードでFatalErrorになるの?

ちなみにBCC5.5はANSI C++には対応していません。
うそ書くなBorland
0026デフォルトの名無しさんNGNG
>>25
23 じゃないけど、たとえばこんなコード。

vector<vector<int> > vv;
for_each(vv.begin(), vv.end(), boost::bind(&vector<int>::resize, _1, 1));

致命的エラー F1004 vv.cpp 14: コンパイラ内部のエラー(関数 main() )
002723NGNG
たしかね、
template <template class<> class C, typename T>
C<T> function() {return C<T>();}
みたいなの。
コードの方が間違ってる気もするんだけど…。
BCC5.5はISO C++と違う部分もいくつかあるけど
(temlate <typename T> friend function<T>();がだめなのは参ったけど)
まあ比較的頑張ってるんじゃないかな。
Windows用コンパイラでもっといいのある?
0028デフォルトの名無しさんNGNG
>>27
Modern C++ Design の著者は、サンプルコードを

 Comeau C++ 4.2.38
 CodeWarrier Pro 6.0

で動作確認した、と書いてある。あとは gcc 3.x 系列じゃないかな。

(妥協して VC7 ってのも現実的な選択肢だと思うけど)
0029デフォルトの名無しさんNGNG
>28
Loki の readme.txt に
> Also, Loki has been ported to gcc 2.95.3 by Nick Thurn.
ってあるよ.
0030デフォルトの名無しさんNGNG
generic programmingというのは、
objectを中心とするような王道OOとは違って、
generic functionを基本とするprogrammingのことね。

C++だと、template、operator/method/function overloadを使う。
0031デフォルトの名無しさんNGNG
Modern C++ Designは、CUJのExpert ForumとかGotWとか好んで見てる人に
とっては必読の1冊ですよね。意外に早く翻訳されたのでよかった。
スマートポインタとかFactoryの話が出たので、ProxyとかFlyweightの例も
欲しかった気がしますが。

メインの開発環境がVisual C++ 6なんですが、Loki全部は通らないみたい。
Windows環境でコンパイル通そうと思ったら、CodeWarriorのWin版か
Cygwin+α的なのに頼ることになりそうですかね?

Lokiのうち、templateのパラメータにtemplate使ってるやつとか、
部分的な特殊化の入ってる部分以外は通ると思ったんで、そいつらを使わない
書きかたで置きかえられるかな、とおもってチャレンジしてみたんですけど
全て敗北しました。「あぁ、こりゃしかたないか」みたいに感じたんですけど、
単に、実力が足りんような気もするし。

部分的に汎用性を捨てて、固定のポリシーで書きなおしてやれば、
それはそれで、それなりに使えるような気もします。

Lokiを使いたいところだけ、通せるコンパイラでライブラリ化してやって
そいつをVC6で使うのはどうだろうかと思ったんですが、それはそれで
ライブラリの名前マングリングの話があって面倒なのでは、とか。
(試してみた人いません?)

いや、、単なる感想で特に言いたいこともないんですが。。。
0032デフォルトの名無しさんNGNG
templateだとexportできないとライブラリ化できないと思う...。
003331NGNG
う、、コンパイル不可なものは所詮をexportするわけにはいかん、と
そういう指摘でしょうか。lokiをコンパイル可能なコンパイラに
templateインスタンスをexportする機能がついているのか、という
お話でしょうか。。

VC++なDLLの場合、templateインスタンスなクラスはexportできるみたいで。
ライブラリ側でポリシーの選択までやっちゃって必要なインスタンスクラスだけ
exportする、という使い方はどうかと。export側とimport側でコンパイラとか
標準ライブラリのバージョンが違って出来上がるバイナリが変わってしまったら
コケるかもしれませんが。

lokiそのものをライブラリ化しよう、というわけではないので、PImplな部分を
lokiで作ってやって、dll exportなインターフェイスをつけてやれば、よいか
と思ったんですが、実行時のパフォーマンスは落ちそうですね。

ライブラリ化してる時点でありがたみ半減には違いないです。
0034デフォルトの名無しさんNGNG
32 の言っているのは、template の前に付ける export キーワードのこと
でしょう。私は、これをサポートしているコンパイラ (というかリンカか?)
って見たことないです。
でも、33 の言うようにテンプレートを個々にインスタンス化したものは、
DLL の意味で export 可能だろうとは思います。
0035デフォルトの名無しさんNGNG
あぁ、exportですか。
なんかで見た記憶があります。プログラミング言語C++第3版だったと思うけど。。
正直いって、どういうしくみになってるのか想像できなかったんですよ、あれは。
テンプレートパラメータが残ってるから。

翻訳単位が違うってことは、テンプレートパラメータが何になってもいいよ、
っていうオブジェクトがあって、それが外部から参照できます、ってこと
ですよね。それってどういう風に実装できるんでしょう、リンカ的に。
なんかいろいろ制約がつきそうですが。
(厨房に解説してやろうというかたお待ちしております)

コンパイル済みオブジェクトにgenericな動作がさせられるっていうのは
なにやら凄そうですが。
0036デフォルトの名無しさんNGNG
勝手な想像ですが、すなおに考えると、export を見た時点ではコンパイラは
たんに export があったということを覚えているだけ。リンク時に未定義な
テンプレートインスタンスが発見されるので、そこで初めてインスタンス生成を
開始。つまりリンカの協力のもとに遅延コンパイルをするという感じかなぁ。
0037デフォルトの名無しさんNGNG
http://research.microsoft.com/projects/clrgen/
に面白い話が載ってるよ。CLRに言語共通なgenericsを導入しようと言う話。
Lazy dictionary creation, JIT, Specialization and Sharingなど、
これまでのlinkerをかなり逸脱する話が含まれてる。(つーか実行時…)
0038デフォルトの名無しさんNGNG
>>37
そのページのタイトル、「COM+ 2.0 Generics」...
0039デフォルトの名無しさんNGNG
>>27
typoがあるYO。

template <template <class> class C, typename T>
C<T> function()
{
  return C<T>();
}
0040デフォルトの名無しさんNGNG
>>39
失礼。書き間違えちゃった。
でも、39のでもダメなんだよね...。これって規格上だめなのかな。
0041デフォルトの名無しさんNGNG
>>40
functio < C < T > >();
じゃだめ?

>>27
>(temlate <typename T> friend function<T>();がだめなのは参ったけど)
これは言語の設計上できないようにしているだけ。
friend classは限定的につかおうってこと
0042デフォルトの名無しさんNGNG
>>41
27 が書きたかったのは、
template<typename T> class Hoge {
frind T function<T>();
};
ということだと思うけど。これは規格上 OK です。つか、function の後の
<T> の有無で意味が変わる。g++ は標準規格に合ってるけど、VC++ なんかは
合っていませんね。
0043デフォルトの名無しさんNGNG
>>27,>>39
うーん、メタテンプレートみたいのを使いたいということ?
これのテンプレート引数の C って、それ自身がテンプレートになってるような
書き方だけど。
でも、そもそもどうやったらテンプレートそのものを引数として渡せるのやら。

004427NGNG
>>42
それは、あのあと確かめたらBCC5.5.1はgccと同じ(規格と同じ)でした。ごめん。
関連することでは、今ISOの規格書読みながらいろいろ試してるんだけど、
template <typename T>
class SampleClass
{
//...
};
の定義の中で、
template <typename T, typename U>
void TestFunction(const TestClass<T> &, const TestClass<U> &);
をfriendにするにはどうしたらいいんでしょう。
BCC5.5.1だとどうやってもエラーになってしまう。
(「宣言が間違ってる」みたいなエラーだから、単なるコーディングミスかも知れない)

あの時書きたかったのは、
template <typename T>
class Hoge {
template <typename U>
friend class Hoge<U>;
};
みたいなのなんです。
(今回も手元にソース持ってきてないので適当に書いてますが...。)
サポートされてない、ってエラーが出ちゃうんだよね。
Effective C++の付録のsmart pointer実装例では使っているので、
規格決定直前に変更になってなければ規格上OKだと思うんだけど。

>>43
template引数にtemplateを使うのは問題ないはずなんだけど...
004527NGNG
ごめん。
class SampleClass
じゃなくて、
class TestClass
です。

コンパイラ通してから書かなきゃだめだね、こりゃ。
004643NGNG
うたがってすまんかった。たしかにテンプレート引数としてテンプレートを
取ることはできるね。でも、その有効な使い道というのがよくイメージできないなあ。
0047デフォルトの名無しさんNGNG
>>46
そのクラスがつかうコンテナを選ぶとか?

cls<vector>
cls<list>
0048デフォルトの名無しさんNGNG
>>44
規格によれば、
template <typename T, typename U>
friend void TestFunction(const TestClass<T> &, const TestClass<U> &);
でよいみたいだけど。でも、クラステンプレートの引数と T がかぶっているのは
まずいかもしれませんね。

friend クラスのほうは、
template <typename T>
class Hoge {
template <typename U>
friend class Foo;
};
でよいみたい。(foo の後の <U> がいらない)) >>44 だと、どちらも Hoge に
なってるけど、それは単なる typo?

0049デフォルトの名無しさんNGNG
>>44
VCではコンパイル通ったよーん。
0050デフォルトの名無しさんNGNG
今読んでる。
普通のC++プログラミングを実数軸の話とすれば、
テンプレートを使った繰り返しや再帰は虚数軸の話だと思った。
抽象度が高すぎるたとえですまぬ。
0051 NGNG
>50
をぃをぃ,それだけじゃ何を読んでるのか分からん人も出て来るだろ.
まぁ Modern C++ Design なんだろうなぁとは思うが.
0052デフォルトの名無しさんNGNG
ごめん、この本専用のスレだと思ってた。
Googleで"Modern C++ design"検索してたまたまこのスレにたどり着いたので。
Functor萌え。
0053デフォルトの名無しさんNGNG
//from "C++ Template as Partial Evaluation"

template<int N>
class Pow
{
public:
 static const int result = Pow<N-1>::result * N;
};

class Pow<1>
{
public:
 static const int result = 1;
};

//...
 const int a = Pow<5>::result;
//...
0054デフォルトの名無しさんNGNG
Factorial じゃないのか??
0055デフォルトの名無しさんNGNG
Functorはやはり関手と訳すのでしょうか?
0056デフォルトの名無しさんNGNG
>>53
>template<int N> class Pow {
>public:
> static const int result = Pow<N-1>::result * N;
こういう場合はstruct Powにしましょう。
非公開メンバー&メソッド無いんですから。

でもGenerativeプログラムの基本やね
汎化と特化のいい関係。
005753NGNG
>>54
そう。スマソ。階乗とべき乗のどっち書くかぼんやり迷ってたから混ざった……。
005853NGNG
>>55
classを類とは訳してないからいいんじゃない?(w
0059デフォルトの名無しさんNGNG
Generic Programmingってさあ、
C/C++のマクロのパワーアップ版って言ったらダメかなぁ。
オブジェクト指向マクロとか。
0060デフォルトの名無しさんNGNG
>>59
結果的にそうなってるだけ。
006153NGNG
>>59
ダメ。機能限定版でもあるから(w。

・マクロはトークンならなんでも置き換えてくれる(予約語さえ)けど、
 templateは型か特定の型の定数しか置き換えてくれない。

・マクロはパラメタのないトークンを置き換えられるが、
 関数テンプレートは関数しか置き換えられないし、
 クラステンプレートを使うには型宣言のときにパラメタ指定が必要。

・マクロ展開の際に引数は文字列として結合ができる
 templateは与えられた引数を文字列として加工する能力はない。

・マクロはプログラムのごく一部にだけ選択的に作用させることもできるが、
 テンプレートはグローバルに影響を及ぼす。

・・・・・・だからマクロとテンプレートには似た性質
(コンパイル時までに処理される)もあるけど、
別のものと思ったほうがいい。
0062デフォルトの名無しさんNGNG
//from "Expression Template Technique"
//(1) Exp<T> and BinOp<T1,T2>

template<typename T>
struct Exp
{
typedef ContType T;
virtual ContType eval(int i) = 0;
};

template<typename T1, typename T2>
struct BinOp : public Exp<T1::ContType>
{
 T1 a1;
 T2 a2;

 BinOp(T1 arg1, T2 arg2)
  :a1(arg1), a2(arg2), op(operation)
  {;}

virtual ContType operation (ContType, ContType) = 0;

 ContType eval(int i)
  {return (operation(a1.eval(i), a2.eval(i)));}
};
0063デフォルトの名無しさんNGNG
//from "Expression Template Technique"
//(2) operators : AddOp<T1,T2> and operator "+" overloading

template<typename T1, typename T2>
struct AddOp : public BinOp<T1,T2>
{
 ContType operation (ContType a1, ContType a2)
  {return (a1 + a2);}
}

template<typename T1, typename T2>
AddOp<T1,T2> operator+ (T1 a1, T2 a2)
{return (AddOp(a1, a2));}
0064デフォルトの名無しさんNGNG
//from "Expression Template Technique"
//(3) Vector<T>

template<typename T>
struct Vect : public Exp<T>
{
 typedef ContType T;
//...
 T* cont;
 int n;

 Vector(int size)
  : n(size), cont(new T[size])
  {;}

 ContType eval(int i)
  {return (cont[i])}

 operator= (Exp<ContType> exp)
  {
  for(int i=0; i<n; i++)
   {cont[i]=exp.eval(i);}
  }
};
0065デフォルトの名無しさんNGNG
//from "Expression Template Technique"
//(4) sample expression

//...
Vector<double> v1;
Vector<double> v2;
Vector<double> v3;
Vector<double> v_res;
//...
v_res = v1 + v2 + v3;
0066デフォルトの名無しさんNGNG
//>>63 訂正
//from "Expression Template Technique"
//(2) operators : AddOp<T1,T2> and operator "+" overloading

template<typename T1, typename T2>
struct AddOp : public BinOp<T1,T2>
{
 AddOp(T1 a1, T2 a2)
  : BinOp(a1, a2)
 {;}

 ContType operation (ContType a1, ContType a2)
  {return (a1 + a2);}
};

template<typename T1, typename T2>
AddOp<T1,T2> operator+ (T1 a1, T2 a2)
{return (AddOp(a1, a2));}
006753NGNG
//>>54 こんどこそPowだと思う(弱気sage)

template<int N, int X>
class Pow
{
public:
 static const int reult =
  (N%2==1)?X:1)*(Pow<(N>>1)>::result)*(Pow<(N>>1)>::result);
};

template<int X>
class Pow<0, X>
{
public:
 static const int result = 1;
};

//...
 const int pow5_5 = Pow<5,5>::result;
//...
0068デフォルトの名無しさんNGNG
>>67
static使うのはまずくない?リンカは削除できるのか?
あとコンパイル時に計算するのにN%2をやるのはなんかけなげ。
コンパイル時間を短縮するための効率的な構造とかてできそうで
怖い。SchemeをコンパイルタイムにやるC++は異常。
0069デフォルトの名無しさんNGNG
>>67
いやいやちょっとまて。static const intが
コンパイル時評価であることは保証されているのか?
てか?文は実行時だろう。とするとこれは
数字を保持したstatic intオブジェクトを
実行時の静的オブジェクト初期化時に順に掛けていくという
クレイジーなプログラムになるんじゃないか?
0070デフォルトの名無しさんNGNG
>>67
static const int じゃなくて enum にすれ。
007171?NGNG
>>67
template<int I,int P>struct Pow{
  enum{R = I * Pow<I,P-1>::R};
};

template<int I>struct Pow<I,0>{
  enum{R = 1};
};
007253NGNG
>>68
テンプレートから展開されるクラス定義の数を減らす効果があるっす。>N%2とPow<(N>>1)>
クラス内のstaticはクラス1つに1個の意味だからそんなに仮に領域が割り当てられていたとしても、
クラス定義を処理する以上には悩ましくはないかと。>static

>>69
プログラミング言語C++第3版 A.5によれば
constant expressionにconditional expression(?: && ||)は含まれるらしいすよ。
ということは評価時に定数になるならば立派に定数式っす。
で、定数式ならコンパイル時に計算され、constに領域は割り当てられない筈。
007353NGNG
具体的には
N=5
ならば
5%2=1 5>>1=2
2%2=0 2>>1=1
1%2=1 1>>1=0
が順に計算できるから
クラス定義の参照関係
Pow<5,X>→Pow<2,X>→Pow<1,X>→Pow<0,X>
という順序に従ってクラス定義が
Pow<5,X>←Pow<2,X>←Pow<1,X>←Pow<0,X>
と展開されていくので
Pow<0,X>::result=1、
Pow<1,X>::result=X*(Pow<0>::result)*(Pow<0>::result)=X、
Pow<2,X>::result=1*(Pow<1>::result)*(Pow<1>::result)=X*X、
Pow<5,X>::result=X*(Pow<2>::result)*(Pow<2>::result)=X*X*X*X*X
の順で初期値が確定する。
007453NGNG
//>>67を一般の引数用に改良、多分展開されるはず。

template<typename T, int N>
class Pow
{
public:
 T operator() (T x)
  {
  T pw = Pow<(N>>1)>(x);
  return (((N%2==1)?x:1)*pw*pw);
  }
};

template<typename T>
class Pow<T,0>
{
public:
 T operator() (T)
  {return (1);}
};

//...
 double pow5_5 = Pow<double,5>(5);
//...
0075デフォルトの名無しさんNGNG
>>74
> 多分展開されるはず。
試してみ。
007653NGNG
>>75
お家にはC++コンパイラ置いてないの(しくり)。今、容量に余裕がなくって。
007753NGNG
とはいえ、
類似のコードは昔論文を読んだときに
g++で試したので、書き損じが無ければ>>74も動作はする筈。
inline展開と定数伝播の程度・能力に関してはコンパイラによるけど。
0078デフォルトの名無しさんNGNG
>>72-74
staticは意味が大きすぎてリンカは削除できないと思う。
5乗の計算に20バイト使う可能性がある!
constもinlineも保証はないので結局残るのはenumだけなんじゃないか?と。
運が悪いと普通のpowになっちゃいますよ的な。
そうして74のintの部分特別化にenumを使えるかなとかなんとか考えると疲れた寝る。
0079デフォルトの名無しさんNGNG
>>78
「意味が大きい」って?
あと20バイトくらいを問題にするなら展開されたコードの方が全然大きいかもよ?(w

大体enumの初期値として処理できる定数式なら
constの初期値として処理できない筈がない。
思うに、展開されたクラスのstatic constについて誰かがアドレス取らない限り
リンカまでも行かないで領域はないと思われる。

ちなみに、
Pow<N,X>::resultは定数式として定数の初期化に使えるところが利点。
Pow<T,N>(x)はNに関しては、
コンパイラが一般の部分特化のアルゴリズムを備えていなくても
テンプレートと定数伝播、inline展開の常識的な実装を備えてさえいれば
確実に部分特化の意図が伝わるのが利点。

初期のcfrontでトランスレートしてた時代ならイザ知らず、
constもinlineもここで出てる例くらいならば、今の最適化技術では
可能不可能の問題でなくやるかやらないかの問題だから、
一般用途のまっとうなコンパイラでは十分できる範囲だと思う。
0080デフォルトの名無しさんNGNG
>>79
だから、とりあえず手元の処理系で試してみろって。
008171?NGNG
>>74
BCCでためしたで
ASM見たけど思惑道理なってるで
0082デフォルトの名無しさんNGNG
>>81
よって問題なし、と。

規格について一通り調べがついた後は、「思う」と書いてあーだこーだ議論するより
実際処理系での結果を出した方が話が早いっしょ。
008353NGNG
>>81-82
どうもです。
今、ようやく試せる環境(研究室の自分の机)にたどり着きました(w。
もう話は終わってるみたいですが。
0084デフォルトの名無しさんNGNG
>>79
20バイトというより1バイトさえも使っては意味がないし
コードが展開されてはそもそもいけない。
コンパイル時評価になることが保証されてこその新しいPow。
Pow<N,X>::resultは、コンパイル時評価は保証されないし
計算ごとに生まれる多くのstatic intが削除されることが
保証されないので恐ろしくて使えない。
Pow<T,N>(x)は、やはりインラインが保証されない上、
インライン展開されてもコンパイル時評価になることが
保証されないので駄目。
いままで標準準拠のコードを書くためにがんばってきたのに
ここでenumを裏切るのはなぜか。
あとcfrontがどうとか言い出すのが好感度下げる。ワラ
008571?NGNG
>>84
いいたいことはわかるが、templateでやる以上、
pow( 2.0 , 3.5 )とかやりたいね。
0086デフォルトの名無しさんNGNG
>>84
完璧確実を求めるならちゃんとPartial Evaluationなり、
2-level Languageなり使うしかないんでは?
元々C++の機能の有り合わせで実現してるんだから。

とりあえず両者とも(仮に最適化されなくても)規格的には最低限動作することになっていて、
少なくとも普及している処理系の一つで意図どおり動作するコードではあるのは確か。

ちなみに実行時にtemplateの展開処理をする珍しいコンパイラでない限り
Pow<N,X>::resultはコンパイル時に定数になっていなければならない。
当然定数式の必要なところでは定数として利用できる。
このコードの本来の目的はそれ。
領域が割り当てられて残るかどうかは副次的なことに過ぎない。
仮に、アドレスを取ったりできるように領域が割り当てられたとしても、
定数伝播の最適化とはまた別の側面の話なので問題はない。
(せいぜいメモリ使用量が増えるだけ。実行速度に悪影響はない。
元々展開テクニックではメモリ使用量ではなくて実行速度に重点が置かれる。)

それに標準準拠って言うけどstatic const intではダメでenumに拘る理由も結局不明。
初期化がコンパイル時に実行できないかどうかは、初期化式の側の問題であって
初期化される変数・定数の側の問題ではない。

裏切るも何も、列挙しない単一の定数の宣言にenumを使うほうこそ
考え様によっては病的だと思うがどうか?
(領域がないことを保証させるための抜け道だということは知っているが、
病的なことに変わりはない。)

あと、>>84君の好感度などはこの際限りなくどうでもよいこと。

もう一つ言えば、
これは標準数学ライブラリのpowを置き換えることを意図したものではない。
Pow<N,X>::resultは定数式の必要なところ(固定長配列の長さとか)で
べき乗の計算を行うために必要なだけのもので、
Pow<T,N>(x)は整数Nを固定したべき乗演算が繰り返される場合に有効なコード。
そういう特殊な用途以外の一般の場合には標準的なライブラリのpow()を使えばよい。

さらに言えば、これはGenerativeなコードをC++の有り合わせで書く場合に利用できる
テクニックを紹介するためのサンプルかつ部品である。
powだけ計算して満足しているわけではない。

>>85
残念ながらx^nのnは整数でないと特化できない。
0087デフォルトの名無しさんNGNG
>85
@sin( 1.46 )とかを展開するような
独自プリプロセサを書けや。
0088デフォルトの名無しさんNGNG
>>87
そんなことせんでもsin(1460000) // =1.46*1000000とかして
1000000で割ればいいじゃん。
古典的手法
0089デフォルトの名無しさんNGNG
>sin(1460000)
sinをテンプレートで実用的にかけると仰る?
0090デフォルトの名無しさんNGNG
>>86
>少なくとも普及している処理系の一つで意図どおり動作するコード
それが駄目だとあれほど。

コンパイル時評価が保証されないので
全くGenerativeではない。君は

賢いコンパイラは仮想呼び出しを実呼び出しに最適化できるので
templateはいらない、仮想関数で十分。
領域が割り当てられて残るかどうかは副次的なことに過ぎない。
せいぜいメモリ使用量が増えるだけ。実行速度に悪影響はない。
多態性にtemplateを使うのは病的。

と思っている。確かにこれは正しい。ワラ
ここでSTLが大好きな君が裏切るのはなぜか。
0091デフォルトの名無しさんNGNG
つまりさあ、87とかの話題ってfixed演算なわけだよね。
そういうことしたいならLISPでプリプロでも書いたほうが自由度高いし簡単。

(defconst var `(,(sin 1.46))) ;;;リストvarにsin(1.46)の結果を埋め込み。

C++もコンパイル時に関数を実行できる仕様だったら便利なのにね。
0092デフォルトの名無しさんNGNG
べつにLISPじゃなくてもいいんだけどね。perlやRubyとかでも。
関係ないけどVBでこういうことができないのは不思議。
0093デフォルトの名無しさんNGNG
>そんなことせんでもsin(1460000) // =1.46*1000000とかして
>1000000で割ればいいじゃん。
まさか・・・
0094デフォルトの名無しさんNGNG
>>91
C++で実装される言語がなにやらほざいているな
0095デフォルトの名無しさんNGNG
STLいいんだけどさぁ、
コンパイルエラー等ででてくる、エラーをどうにかしてほしい。
0096デフォルトの名無しさんNGNG
>>95
『STL Error Decryptor』
 http://www.bdsoft.com/tools/stlfilt.html
みたいなものを使ってみるとか。
0097 NGNG
>96
をぉ!それは便利そうだ!!!!
と思ったら VC 用かよ・・・
残念sage
0098デフォルトの名無しさんNGNG
>>90
もう、その話題は良いって。

使えると思うヤツは自分のコンパイラで試した上で使えば良いし、汎用性が
必要なプログラムを書いてる場合には、それなりの対処しろ。
0099デフォルトの名無しさんNGNG
>>98
Genericが汎用って意味なのだが
0100デフォルトの名無しさんNGNG
>>99
言葉遊びは、技術系の板の外でな。

Generic Programming を Win32 API と組み合わせてプログラミングしたって
良いじゃない。
0101デフォルトの名無しさんNGNG
「入門C言語」とか銘打っておいて、なかみをみると
いきなりWinMainからはじまったりすると激しく萎える。
■ このスレッドは過去ログ倉庫に格納されています