Generic Programming with C++ Template
■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさん
NGNG参考図書:
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/
0352デフォルトの名無しさん
NGNGたぶん、キミがおかしい。
VC7 のことはよくわからんけど、ふつう swap は <algorithm> の中で
次のように定義されているはず:
namespace std{
template<class T> inline void swap(T& x, T& y) { … }
}
で、何か標準ヘッダーをインクルードして、using namespace std;
してるでしょ? それで、1行目の swap とバッティングしてるんだと
思うけど。
ちなみに、2行目の swap は関係ない。それを外してもエラーが出るん
じゃない?
0353デフォルトの名無しさん
NGNGusing namespace std はやめよーよ。
0354デフォルトの名無しさん
NGNG例が悪かった・・
swapじゃなくてなんでもいいです。
とにかくテンプレート関数をクラステンプレートで特殊化しようとすると
特殊化優先順位で弾かれる。
名前空間とは関係ない問題です。(これが後々関係してくるが)
0355デフォルトの名無しさん
NGNGtemplate<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前半部分、13.5.1(p.404) によって後者が選ばれなきゃいけない話?
gcc 2.95ではちゃんと選ばれたよ。
0358デフォルトの名無しさん
NGNGC++の本を見る限りではそのgccの動作が正しいと思うんだけど。
VC7では選ばれる以前にコンパイルエラーになる。
多分、テンプレート関数とクラステンプレートで特殊化したテンプレート関数の
特殊化優先順位が等しいからこんなことになる。
これだったらすぐ直りそうなもんだからSPで直してほしい・・
0359デフォルトの名無しさん
NGNGC++のテンプレートの仕様を把握するのが一苦労って事なのかな?
0360デフォルトの名無しさん
NGNG違う名前空間の関数を特殊化するなという意味だろうか。
Javaみたく階層的に名前空間分けてたら
同一プロジェクトでも同じ問題が発生するが・・
共通関数を使わずメンバ関数を使えという話になるんだろうけど
それだとSTLのうまみも半減だわな
ところでクラステンプレートをクラステンプレートで特殊化って
C++的に可能なの?VCではダメだった。
0361デフォルトの名無しさん
NGNG0362デフォルトの名無しさん
NGNGBorland-C++ 5.6では正しくコンパイルできますた。
0363デフォルトの名無しさん
NGNG0364デフォルトの名無しさん
NGNG0365デフォルトの名無しさん
NGNGでDLしたらVC.NETじゃコンパイルできねージャン!!
氏ねMS!IDEばっか凝ってねーでコンパイラ改良しる!
0366デフォルトの名無しさん
NGNG ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄」
―――――――――――――‐┬┘
|
____.____ |
| | | |
| | ∧_∧ | | C++を窓から投げ捨てろ
| |( ´∀`)つ ミ |
| |/ ⊃ ノ | | C++
 ̄ ̄ ̄ ̄' ̄ ̄ ̄ ̄ |
--------------------------------------------
0367デフォルトの名無しさん
NGNGそもそもMSがcl.exeをANSIに完全対応させる気がないのだとしたら
どういう事態になるんだろう。
0368デフォルトの名無しさん
NGNG0369デフォルトの名無しさん
NGNGenum {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なぜ順番を変えようとする?
0372デフォルトの名無しさん
NGNGVBAかなにかでボタン一個でソース吐くようにしとけば?
俺だけかもしらんが、よくやってるよ。
その場限りならセルに文字列適当に連結する式かいてコピペ、とかもやるし。
0373デフォルトの名無しさん
NGNG見栄えが気にくわなくてあっち入れ替えたりこっち動かしたりする時期があるもんさ。
0374デフォルトの名無しさん
NGNG0375デフォルトの名無しさん
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;
}
0376375
NGNG今頃気づいたけど、呼び出し時のインデックスはコンパイル時には確定してないのか・・・じゃ駄目だ。
0377375
NGNGちょっとオーバーヘッドがあるけど、
(テンプレートクラス内の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> Function<HOGE>::call,
> Function<HAGE>::call
> };
それだと結局、enumを
enum {HAGE,HOGE,};
に変えられたときにマズーではないか?
0379375
NGNGやっちまった(藁
0380デフォルトの名無しさん
NGNGちょっとなぁ、という気がする。
自分が書くにはいいが、人には見せられない。
そもそも、見栄えを気にする(順番を入れ替える)んだから、
その書き方はいいとは思えない
0382375
NGNGenum値と対応させるってことは配列のインデックスは手打ちでenumの値を書くってことだろ?
インデックスが実行時に決まるならenumに対応させる意味もないし。
0383デフォルトの名無しさん
NGNGHAGE,
HOGE,
};
template<int i>
void f();
template<>
void f<HAGE>()
{
return;
}
void f<HOGE>()
{
return;
}
void (*func[])() = {
f<HAGE>,
f<HOGE>,
};
0384デフォルトの名無しさん
NGNG0385369
NGNGどうやればいいのかはさっぱり分かりませんけど。
>>382
いや、呼び出すときは (*func[n])() ですが…。
対応させる意味がない…? えーと。考えます。
0386デフォルトの名無しさん
NGNG0387デフォルトの名無しさん
NGNGテーブルを動的に作るのはだめなん?
0388デフォルトの名無しさん
NGNG俺もそう思う。
0389369
NGNGエンコーダとデコーダを作ってまして。
エンコーダは、テキストの文字列 "hoge" "hage"を読み込んで、
バイナリでenum値「HOGE,HAGE」を吐きます。んで、
デコーダは、バイナリでHOGE,HAGEをみて、関数hoge(),hage()を呼ぶ、と。
そういう状況です。
>>テーブルを動的に
いや、いいんですけど。でも、静的に解決できることじゃないですか。
出来たらかっこいいじゃないですか。そういうスレじゃないですか、ここは。
0390デフォルトの名無しさん
NGNGもし出来たとしても決してかっこよくはならないと思うぞ。
0391デフォルトの名無しさん
NGNGusing 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それだったら、
std::map<std::string, void(*)()> m;
m["hoge"] = hoge;
これでいいじゃん。
0393デフォルトの名無しさん
NGNG試みとしてはおもしろいかな。
でも、おれの知識じゃまだ無理だなあ。
Modern もっとよむか
0394デフォルトの名無しさん
NGNGそれがもの凄く伝わってくるスレ
0395デフォルトの名無しさん
NGNG改造してみた、本末転倒?
#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全然かっこよくないぞ
0397デフォルトの名無しさん
NGNG0398369
NGNG0399デフォルトの名無しさん
NGNGModern(の前半)読んでかっこいいと思ったか?
俺は、すげぇとは思ったがかっこいいとは思わなかったよ(むしろ汚い)。
このスレで今やってることも同じようなもんさ。
おとなしく動的作成にしない389が悪い。
0400デフォルトの名無しさん
NGNG#include "stdafx.h"
をソースファイルの先頭に入れ忘れてるとか。
0401デフォルトの名無しさん
NGNGVCだとバグのせいでうまくいかなかったはず。
たしか、すべて同一の実体を指すようになってたような。
0402デフォルトの名無しさん
NGNG他のに乗り換えれ。
0403デフォルトの名無しさん
NGNGtemplate <int i> void func()
{
std::cout << i << std::endl;
}
int main()
{
func<0>();
func<1>();
return 0;
}
これをコンパイルしてみればわかる
0404デフォルトの名無しさん
NGNG0405369
NGNG0406デフォルトの名無しさん
NGNGtemplate<int i> class func {
public:
func() {
std::cout << i << std::endl;
}
};
0407デフォルトの名無しさん
NGNG0408369
NGNGで、あとは391と組み合わせれば…?
0409369
NGNGどうすれば…。
0410デフォルトの名無しさん
NGNGヒント
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デフォルトの名無しさん
NGNG0412デフォルトの名無しさん
NGNG最悪だな
0413デフォルトの名無しさん
NGNG0414デフォルトの名無しさん
NGNG********************** 終了 ************************
0415369
NGNG>>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デフォルトの名無しさん
NGNG0417デフォルトの名無しさん
NGNG0418デフォルトの名無しさん
NGNG0419デフォルトの名無しさん
NGNG0420369
NGNG ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄∨ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
∧_∧
( ´Д⊂ヽ
⊂ ノ
人 Y
し (_)
(´-`).。oO(っていうか、考えついたのが満足であって、>>415を使ったりはしないけどね…)
(´-`).。oO(.NETなら>>395を使えるのかしら?)
0421デフォルトの名無しさん
NGNGでも誰も使うことはないだろう。
0422デフォルトの名無しさん
NGNGこれが実戦と同じだと勘違いしたら問題だが、
こういう鍛え方でしか鍛えられないことはある。
どんどんやるべきだと思うよ。
0423デフォルトの名無しさん
NGNG運動するための筋トレはまったく別物。
鍛え方を間違っちゃいかん。
0424デフォルトの名無しさん
NGNG0425369
NGNG通ることに気付いてしまいました。
#include <iostream>
using namespace std;
class Hoge
{
public:
void operator()(void){cout<<"hoge"<<endl;}
};
int main(){
Hoge()();// ←なんと奇怪な構文!
return 0;
}
…うわー。これ、ホントに通っていいんですか? まあ、理屈には合ってますけど…。
(最初のカッコでHogeのデフォルトコンストラクタでテンポラリインスタンスを生成。
次のカッコでHogeのoperator()を呼び出す)
VCだけじゃないことを祈りまふ…。
ちとスレ違いかな。sage.
0426デフォルトの名無しさん
NGNGそれ、普通だが?
文が完了するまで一時オブジェクトの寿命が続くはず。
Hoge(), foo(), bar();
こうすると、bar()の後にHogeのデストラクタが呼ばれる
0427369
NGNGコンストラクタやoperator()の引数次第で、関数宣言だとか
関数ポインタだとか、そのあたりと間違えてしまいそうな構文だなーと。
0428デフォルトの名無しさん
NGNG0429デフォルトの名無しさん
NGNGstruct Hoge { Hoge& operator()(void){return *this;} };
int main() {
Hoge()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()();
}
…はともかくとして、何の変哲もないふつうの構文だと思うよ。
> 関数宣言だとか関数ポインタだとか、そのあたりと間違えてしまいそうな構文
引数付きのコンストラクタを呼び出したりする時に、
下手すると関数宣言扱いになっちまうことはあり。
Effective STLとか参照。
0430デフォルトの名無しさん
NGNGそれ、Cでも通らん?
#include<stdio.h>
typedef void (*fp)(void);
typedef fp (*fpp)(void);
void hogegege(void)
{
printf("\nhogegege\n");
return;
}
fp hogege(void)
{
printf("\nhogege\n");
return(hogegege);
}
fpp hoge(void)
{
printf("\nhoge\n");
return(hogege);
}
int main (int argc, char argv[])
{
hoge()()();
return(0);
}
----
/tmp>gcc hoge.c
/tmp>./a.out
hoge
hogege
hogegege
/tmp>
0431デフォルトの名無しさん
NGNGしかしそれはC++信望崩壊への、ほんの序曲でしかなかった──────。
425「げ、良く考えたらどれもこれも、Cで作れるじゃん!」
430「それ、Cでも通らん?」
413「はっきりいって、ここまでしてやることじゃないと思う」
426「それ、普通だが?」
425「し、Cマンセー!C++なんてクソ。これ定説!」
だれかprojクトX風に仕立ててくれ。
0432デフォルトの名無しさん
NGNG\ ヽ / /ソ
プ ロ ジ ェ ク ト\ ヽ P r o j e c t X
─────────────────────
Generatorたち /|_/ /\Generators
| / \ 丶
\/ \__ノ
Genericスレッド。
このスレで425は一人で悩んでいた。なぜこんな構文が許されるのかと。
「いや、関数オブジェクトでは当たり前だ。」
「こんな物は普通だ。」
次々とヤジが飛ぶ。へこんだ。
万策尽き果てたとき、ふと430が現れる。
「Cでも出来るんじゃないか?」
これは、C++に翻弄された男たちの物語である。
風の中のスバル〜♪
0433デフォルトの名無しさん
NGNG1+-+-+-+-+-+-+-+1 とか
0434デフォルトの名無しさん
NGNG0435425
NGNG一応、マジフォロー。
Hoge()()()
がCでも関数ポインタを使えば構文上は通るとは言っても、
もちろん単なる関数ポインタと関数オブジェクトでは意味合いは大分違う。
たとえば、ベキ級数アルゴリズムを抽象化したクラスを考える:
class PowerSeries {
private:
int n;
double* coef;
public:
PowerSeries(double* coefficients, int number_of_coefficients)
n(number_of_coefficients), coef(coefficients){;}
double operator(double x){
double rst = coef[n];
for(int i = n - 1; n >= 0; i--){
rst *= x;
rst += coef[i];
}
return (rst);
}
};
このように関数オブジェクトではコード(級数計算アルゴリズム)に対して
それをカスタマイズするようなデータ(係数データ)を付加することができるが、
関数ポインタではできない。
この例は一種のCurry化であるが、一般にこのようなことを記述するには
「データを付加できる関数ポインタのようなもの」が必要になる。
もし高階関数型言語ならば、関数を返り値として関数クロージャーを利用すれば、
クロージャーにこのようなデータを記録できるが、C/C++には
高階関数がないので関数オブジェクトが必要となる。
Genericプログラムにおける関数オブジェクトの効用もそこにある。
0437430
NGNG誤>double operator(double x){
正>double operator() (double x){
0438デフォルトの名無しさん
NGNGコピーを渡すことになるのでクロージャのデータは破棄されることになる。
0439430
NGNG誤>ベキ級数アルゴリズムを抽象化したクラス
正>ベキ級数を抽象化したクラス(評価にホーナーのアルゴリズムを使う)
0440430
NGNGC/C++のオブジェクトの代入セマンティクスでは
デフォは参照じゃなくてコピーざんすからねぇ。
受け渡したいデータの性質と意味に応じてコピー・コンストラクタあたりで
なんとか頑張るしかないでしょうなぁ。
0442デフォルトの名無しさん
NGNGstd::transformに渡す関数オブジェクトって副作用があっちゃダメってことですけど、
これの具体的な根拠ってどこにあって、
実際どういう不具合が考えられるのかわかりますか?
状態変数のようなものを内部に持てるのが関数オブジェクトのいいところだと
思っていたのですが、これはつまり、副作用を期待して呼び出す std::for_eachと
はちがって操作対象の変換(のみ)を純粋に扱うstd::transformが呼ぶ関数オブジェクト
は副作用があってはいけない、といういみでしょうか。
たとえば、
呼び出されるたびに内部カウンタをインクリメントした値を加算する変態加算関数オブジェクト
struct addinc : std::unary_function<int, int> {
addinc(int serial = 0) : serial_(serial) {}
int operator()(int n) { return n + serial++_; }
private:
int serial_;
};
みたいなのは、transformに対して使用するには不適切、ということでしょうか?
それとも関数オブジェクト呼び出しがconstかどうかが問題であって、
int operator()(intn)をconstメンバに、int serial_をmutableとかにしちゃえば
セマンティクス的にもOKというわけなんでしょうか?
0443デフォルトの名無しさん
NGNG0444デフォルトの名無しさん
NGNG> std::transformに渡す関数オブジェクトって副作用があっちゃダメってことですけど、
これ初耳なのだがどこに書いてあったん?
0445デフォルトの名無しさん
NGNG今SGIのSTLのドキュメントを読みましたが、そんなことは書いてないですね。
0446デフォルトの名無しさん
NGNGttp://www.cuj.com/experts/1902/langer.htm?topic=experts
には
Requires: op shall not have any side effects
みたいなことが書いてありますね。
Effective STLかなにかにもtransformに渡すのは述語でなきゃいかん、みたいな
ことがあった気がします。(今手元にないので確認できません。)
0447デフォルトの名無しさん
NGNGEffective STL 39項がそのものズバリの解説になっている気がする
0448デフォルトの名無しさん
NGNGありがとーございましし。
0449430
NGNGこの場合言われてる「副作用」は厳密な参照透明性
(、内部状態変数やグローバル変数への代入、入出力禁止とかを含む)
とかじゃなくて、与えられた引数(イテレータ)の指すオブジェクトを
書き換えてはイカンということなんじゃ?
0450430
NGNGC++標準テンプレートライブラリ
は
The C++ Standard Template Library
(P.J.Plauger他著、)の邦訳(ピアソン・エデュケーション刊)ね。
■ このスレッドは過去ログ倉庫に格納されています