トップページ⇒tech
1001コメント388KB

【C++】template 統合スレ -- STL/Boost/Loki, etc.

■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさんNGNG
C++ のジェネリックプログラミングの話をしましょう。
以下のスレッドを統合するスレです。

STLスレッド
Part1 http://pc.2ch.net/tech/kako/1004/10042/1004287394.html
Part2 http://pc3.2ch.net/test/read.cgi/tech/1026793823/

【C++】Boost使い集まれ!
http://pc3.2ch.net/test/read.cgi/tech/1033830935/

Generic Programming with C++ Template
http://pc.2ch.net/tech/kako/1008/10085/1008593126.html

関連スレ、その他リンクは >>2-5 あたりに。
0305デフォルトの名無しさんNGNG
>>304
(*it)はnewで作成したstringを
コピーコンストラクタでコピーした物だからダメだと思うが。
0306303NGNG
>>304-305
えっと、つまり、
void foo() {
string* p;
std::vector<std::string> v;
v.push_back( *(p = new std::string("美幸...おまえ...") );
delete p;
}
ってやらなきゃだめ、ってことですか?
0307デフォルトの名無しさんNGNG
>>306
そのコードだと、↓といっしょだな。
void foo() {
std::vector<std::string> v;
v.push_back( "美幸...おまえ..." );
}
0308303NGNG
うん、えっと、std::vectorが、
「なにを保持してるのか、どう扱えばいいのか」を知りたかっただけなのです。
そか、307見たいに書けるって事は、
「std::vector::push_backは、引数を基にして、
変換コンストラクタかコピーコンストラクタで新しいインスタンスを作って、
そのインスタンスを保持する」
ってことだよね。

新しいインスタンスを保持するんだから、
元のインスタンスは自分で解放する必要がある、と。

やっと心のもやもやが。ありがとうでした。
0309デフォルトの名無しさんNGNG
「TIME」誌2002年の顔にアラファト議長を! 3
http://live.2ch.net/test/read.cgi/festival/1040234682/

急募!投票ツール作れる方
97式アラファトマシンガンが無効に!  
アラファトの票がリセット!
0310デフォルトの名無しさんNGNG
次のコードがコンパイルできないんですけどなぜ?

#include <iostream>
template <class T>
struct Hoge
{
    friend void func()
    {   std::cout << "フレンド関数なんだけど" <<std::endl; }
};

int main()
{
    func();
}

VC7では、「error: C2065: 'func': 定義されていない識別子です」とおこられます。
#定義してあんだけどなあ〜
0311デフォルトの名無しさんNGNG
>>310
'func' なんてどこにも定義してないだろ。
0312デフォルトの名無しさんNGNG
しかし、310 の friend void func() は、どうやって呼べばいいんだ?
0313310NGNG
>>311 >>312
func() はフレンド関数だから、グローバルスコープのはずですけど
0314デフォルトの名無しさんNGNG
template <class T> って書いてある奴の何がグローバルスコープなんだ?
0315デフォルトの名無しさんNGNG
template Hoge<int>;
int main()
{
func();
}
かな。ま、func() が何かHoge型の引数をとってくれないと無意味だわな。
0316デフォルトの名無しさんNGNG
ということで310はtemplateのインスタンス化について小一時間勉強すること。
0317デフォルトの名無しさんNGNG
#include <iostream>
template <class T>
struct Hoge
{
friend void func<T>()
};

template<class T> void func()
{ std::cout << "フレンド関数なんだけど" <<std::endl; }

こうするはず
0318310NGNG
>>314
template <class T> はHoge に付いているんで、メンバじゃない func() には関係ないと思うけど。

>>315、>>316
動きました。でもなぜ?
func() は普通の関数じゃないの? テンプレートじゃない普通の関数をインスタンス化?
0319デフォルトの名無しさんNGNG
> テンプレートじゃない普通の関数

どうしてそう思うのか訊きたいのだが
0320316NGNG
だから規格書嫁って。
14.5.3
-5- When a function is defined in a friend function declaration in a class template, the function is defined at each instantiation of the class template.
0321310NGNG
>>319
フレンド関数が func() が テンプレート Hoge のメンバじゃない、っていうのは正しいですよね。
Hoge のtemplate <class T> は、クラスそのものとメンバに対してしか影響せず、パラメータに依存しているわけでもない func() とはまったく関係ないはず。
func() 自体も関数テンプレートとして定義されているわけじゃない。

だから普通の関数だと思うんだけど。
0322310NGNG
>> 316
へえ、普通の関数でも、個別にインスタンス化されるんだ。
勉強になりました。
でも、ということは、インスタンス化されるごとに同じ定義が再生産されることになるの?
それってやぱくない? 
って、VC7はHoge を複数インスタンス化してもエラーになんないな。大丈夫なのかな?
0323デフォルトの名無しさんNGNG
そのネタくさい物言いなんとかしてください。それにこれは
どっちかというと相談室の方でやる質問なのでは?
0324310NGNG
>>323
>そのネタくさい物言いなんとかしてください。
それは正直、すまんかった。きおつけるよ
>それにこれはどっちかというと相談室の方でやる質問なのでは?
template がらみだから、こっちに投げたけど、こんどからはそうするよ。
0325デフォルトの名無しさんNGNG
タイトルは s/template/generics/ のほうがよかったかもね
0326デフォルトの名無しさんNGNG
関数テンプレートの関数のアドレスって取ることができないの?

template <typename T>
class Hoge {
T i;
public:
Hoge(T t) : i(t) {}
friend void func<>(Hoge<T>&);
};

template <typename T>
void func(Hoge<T>& t)
{
std::cout << "フレンド関数なんだけど" << std::endl;
std::cout << t.i << std::endl;
std::cout << reinterpret_cast<long>(&func) << std::endl;
}

int main()
{
Hoge<int> h(123);
Hoge<int> i(456);
func(h);
func(i);
}
0327デフォルトの名無しさんNGNG
>>326
質問内容と貼り付けるソースを対応させてくれ。
ソースがいろんな(たぶん余計な)要素を含みすぎて
何を答えて欲しいのかがイマイチつかめん。

そのソースでエラーになるんだったら、&func<T>かなー?
0328デフォルトの名無しさんNGNG
>>327
スマソ。いらない要素を除いて短くしました。まだエラーが出ます。
コンパイラはgcc3.2.1(MinGW)です。

template <typename T>
class Hoge {
friend void func<>(Hoge<T>&);
};

template <typename T>
void func(Hoge<T>& t)
{
std::cout << reinterpret_cast<long>(&func<T>) << std::endl; //エラー
}

int main()
{
Hoge<int> h;
Hoge<int> i;
func(h);
func(i);
}
0329デフォルトの名無しさんNGNG
さらに短くしました。friend宣言もクラス宣言も取ってしまいました。

template <typename T>
void func(T t)
{
std::cout << t << std::endl;
std::cout << reinterpret_cast<long>(&func<T>) << std::endl; //エラー
}

int main()
{
func<int>(1);
}
0330デフォルトの名無しさんNGNG
329です。自己解決しました。
テンプレート関数は、コンパイラから関数のオーバーロードと解釈されるようです。
従って、関数名を正しくキャストする事によりうまくコンパイルできました。

template <typename T>
void func(T t)
{
std::cout << t << std::endl;
std::cout << reinterpret_cast<long>(static_cast<void (*)(T)>(func)) << std::endl; //うまく行く
}

int main()
{
func<int>(1);
func<double>(1);
func<int>(2);
}
0331デフォルトの名無しさんNGNG
んーでも少し問題が。gcc3.2.1(MinGW)では通るものの、Borland-C++5.6.2では

エラー E2335 overload2.cpp 7: このコンテキストではオーバーロード 'func' が曖昧(関数 void func<int>(int) )
エラー E2335 overload2.cpp 7: このコンテキストではオーバーロード 'func' が曖昧(関数 void func<double>(double) )

と言われてしまいました。Borland-C++が糞なのか、それとも私が何か間違っているのか?
0332デフォルトの名無しさんNGNG
Modern C++ Design を読んで疑問に思ったので質問します
8章のオブジェクトファクトリのRegisterコールバック関数の登録についてです。
ある具象クラスLine(: public Shape)のソースにおいて
const bool registered = ShapeFactory::Instance().Register( LINE, CreateLine );
としてシングルトンのファクトリに登録していますが、
これはファクトリがシングルトンの場合にしかつかえないと思うのです。
動的にファクトリを生成・利用する場合には、具象クラスの情報を一ヶ所にまとめた物がどこかに必ず必要になると思うのですが、
この認識は正しいでしょうか?
シングルトンではなく、ファクトリになんの変更も無しに新たな具象クラスを追加する方法があるのでしょうか?
0333デフォルトの名無しさんNGNG
VC.NETのSTLへの対応ってどんなもんなんですか?
VC6.0と同じ程度なんですか?
sort(v.begin(),v.end(),mem_fun_ref(&hoge::hoge)); ←こんなの通るの?
0334デフォルトの名無しさんNGNG
>>332
Factoryクラスのstaticメンバに情報を持つか、FactoryのFactoryに
情報をまとめるようにして、Factoryの生成をライブラリ側で管理するか、
フリー関数のオーバーロードで頑張るかすれば、一応何とか出来るのではないかと。

しかし、ファクトリがSingletonでないことが必要な場合なら、
各々のファクトリが勝手に情報共有してしまったらむしろ
困ると思うのだけど、具体的にどういう場合を想定してるん?

>>333
> mem_fun_ref(&hoge::hoge)
いやコンストラクタをmem_funに渡せる実装はなかなか少ないだろう。

men_fun1_refにしないでも大丈夫になってるか?という意味なら、VC.NET 2002 ならOK。
0335デフォルトの名無しさんNGNG
>>334
すいません、編集ミスです。<コンストラクタ
しかも、ペーストする場所を思いっきり間違えてました。
質問したいのは、これ(↓)でした。
find_if(v.begin(),v.end(),bind2nd(mem_fun_ref(&Hoge::hoge),HogeObject));

手元にg++用に書かれたコード(STL多用)があり、
これにGUI部分を実装しなければならないのですが、
VC6までは、STLがまともに動かないという話を聞いたことがあるので、
VC.NETではどうなってるのかなと思って質問しました。
やっぱり、BCB6の方が良いでしょうか?
0336332NGNG
>>334
疑問に思っていたのは以下の2点でした
・「シングルトン」及び「staticメンバに情報を登録」ではプログラムロード時からメモリに存在する。
・ファクトリ側では実行するまでどんな具象クラスが登録されるかを知らない形にし、各具象クラスのcppファイルで登録させる。

プログラムの流れでたまにしか出てこない、いろんな種類のファクトリをはじめからメモリに確保するのが嫌だったのです。
でも実行時に登録するには、
・コンパイラが自動的に実行してくれるグローバルな領域に置かれた命令による登録(シングルトンが必要)
・どこかにリストアップしておく。
のどちらかしか無いように思います。
用語が滅茶苦茶だと思いますがすいません。
0337sageNGNG
>・コンパイラが自動的に実行してくれるグローバルな領域に置かれた命令による登録(シングルトンが必要)
グローバルはおかしいかな。
cppファイルの頭の部分に書く
const bool registered = Singleton::Register(objType,CreateCallback);
な感じのやつのことです。
0338デフォルトの名無しさんNGNG
ファクトリの百や二百、メモリを使用してるうちに入らんと思える私は幸せなのでしょうか。
0339332NGNG
私もです。しかもせいぜい10個くらい。
0340デフォルトの名無しさんNGNG
std::mem_fun_refってどういう時に使う?
std::mem_funは、仮想関数を呼び出す時に便利だが、std::mem_fun_refだと
クラスへのポインタではなく実体を渡さないといけないので、例えば

class A;
class B : public A;

のようになっているとして、

std::vector<A*> にはBへのポインタも格納できるが、std::vector<A>にBを
格納しようとすると未定義の動作となる。ポインタならばstd::mem_funで
呼び出せる。std::mem_fun_refは実体を渡さなければならないが、vector
に両方は格納できない。

だから、std::for_each()などで、std::mem_fun_refを使う状況というのがどう
いう場合なのか知りたい。
0341デフォルトの名無しさんNGNG
>>340
Aが派生して使うような型じゃない場合。
0342デフォルトの名無しさんNGNG
>>341
なるほど、こんな場合か。単純と言えば単純だな。

class A {
int j;
public:
void print(int i) {
std::cout << i + j << std::endl;
}
A(int k) : j(k) {}
};

int main()
{
std::vector<A> a;

a.push_back(A(1));
a.push_back(A(2));
a.push_back(A(3));

std::for_each(a.begin(), a.end(), std::bind2nd(std::mem_fun_ref(&A::print), 1));
}
0343デフォルトの名無しさんNGNG
boost::anyと、std::mem_fun_refを使って仮想関数を呼び出そうとしたが
なかなかうまく行かない。

int main()
{
std::vector<boost::any> a;

a.push_back(A());
a.push_back(B());

std::for_each(a.begin(), a.end(), std::bind2nd(std::bind1st(std::mem_fun_ref(&A::print), boost::any_cast<A&>(this)), 1)); // だめ
}
0344デフォルトの名無しさんNGNG
どうしてany_castに失敗するのでしょうか?

struct A {
void print() {
std::cout << "A" << std::endl;
}
};
int main()
{
std::vector<boost::any> a;

a.push_back(A());
a.push_back(A());

std::vector<boost::any>::iterator pos = a.begin();
try {
for (; pos != a.end(); ++pos)
boost::any_cast<A>(a).print();
}
catch (boost::bad_any_cast& e) {
std::cerr << e.what() << std::endl;
}
}
0345デフォルトの名無しさんNGNG
>>343
試さずに書いてるが、
boost::compose_f_gx( boost::bind( &A::print, _1, 1 ), &boost::any_cast<A&> );

>>344
boost::any_cast<A>(*pos).print();
じゃねーの?
0346345NGNG
というか、今のバージョンのany_castって継承関係の把握できたっけ。
0347デフォルトの名無しさんNGNG
Lokiのインストール法、誰か教えて。
英語読めん。
それと、iostreamをインストールすると、コンパイラ付属のは使えなくなるんか。
それはそれで不安だ。教えてくれ。
0348デフォルトの名無しさんNGNG
>>347
DLして解凍して適当なフォルダに入れてインクルードパス通すだけ
というかあれくらいの長さのreadmeくらい読みなよ…

後環境も何も書いてないからこれ以上は無理
0349デフォルトの名無しさんNGNG
Lindows
0350デフォルトの名無しさんNGNG
>>345
ありがとうございます!

boost::compose_f_gx( boost::bind( &A::print, _1, 1 ), &boost::any_cast<A&> );
は通りませんでしたが、

boost::any_cast<A>(*pos).print();
は無事通りました。

boost::any_castは依存関係の把握はできないかもしれませんので、ポリモルフィズム
には使わないようにします。
0351デフォルトの名無しさんNGNG
ところで C++ Templates [ http://www.josuttis.com/tmplbook/tmplbook.html ;] は既出なのか?
0352名無しさん@EmacsNGNG
げ、ホントだ、any_cast ってポリモーフィズムに使えないんだ・・・
っつーか皆さん boost::any ってどんな時に使ってます?
イチイチ any_cast 噛まさにゃならん上にポリモーフィズム使えないもの
をどんな風に使うのか興味があるのですが・・・
# つまり馬鹿だから使い道が思い付かないわけでして。

struct A { virtual void print() { std::cout << "A" << std::endl; }};

struct B : public A{ virtual void print() { std::cout << "B" << std::endl; }};

int main()
{
std::vector<boost::any> a;

a.push_back(new A());
a.push_back(new B());

std::vector<boost::any>::iterator pos = a.begin();
try {
for (; pos != a.end(); ++pos) boost::any_cast<A*>(*pos)->print();
}
catch (boost::bad_any_cast& e) {
std::cerr << e.what() << std::endl;
}
}

output>
A
boost::bad_any_cast: failed conversion using boost::any_cast
0353デフォルトの名無しさんNGNG
>>352
void* で汎用パラメータ渡し…とか、union でノードの種類を区別した
木構造…とかのtypesafeなバージョンとしては、とりあえず超高速で
お手軽に書こう、と思ったときには使えるかも。俺は使ったこと無いけど。

using namespace boost;
struct add { add(any l,any r):left(l),right(r){} any left, right; };
struct mul { mul(any l,any r):left(l),right(r){} any left, right; };

double eval_expr( any e )
{
if( e.type() == typeid(add) ) {
add ex = any_cast<add>(e);
return eval_expr( ex.left ) + eval_expr( ex.right );
} else if( e.type() == typeid(mul) ) {
mul ex = any_cast<mul>(e);
return eval_expr( ex.left ) * eval_expr( ex.right );
} else if( e.type() == typeid(double) ) {
return any_cast<double>(e);
} return any_cast<int>(e);
}

int main()
{
any expr = add( add(mul(6,7),2), mul(3,4) );
cout << eval_expr( expr ) << endl;
}

その手の使い方をするにしても、入れられる型に制限をつけた
variantとかの方がマシだしなぁ。
0354デフォルトの名無しさんNGNG
>>351
any.hppの中身を見てみると、boost::any_castはキャストしようとする型と、
元のタイプのtypeidを比較して、一致しないとキャストしないようになっている。
だからポリモルフィズムに使えないんだろう。

-- any.hpp (STLpotrt)より

template<typename ValueType>
ValueType * any_cast(any * operand)
{
return operand && operand->type() == typeid(ValueType)
? &static_cast<any::holder<ValueType> *>(operand->content)->held
: 0;
}

std::mem_fun_refと組み合わせていろいろと面白い事をやらせようとしていた
のだが、使えねー。まあだめならだめで昨日から悩み続けていた事が解決
したのでいいのだが。
0355デフォルトの名無しさんNGNG
スマソ>>354は>>352さんに対するレスです。
0356デフォルトの名無しさんNGNG
すごく簡単な所でつまづいています。どこがおかしいのでしょうか?

class A {
public:
void func(int i) {
std::cout << i << std::endl;
}
};

int main()
{
std::vector<A> a;

a.push_back(A());
a.push_back(A());

std::for_each(a.begin(), a.end(), std::compose1(std::mem_fun_ref(&A::func), 1);
}
0357デフォルトの名無しさんNGNG
自己解決しました。うーん?直感的にはcompose1のような気がするのですが?
わからなくなってきた。

class A {
public:
void func(int i) {
std::cout << i << std::endl;
}
};

int main()
{
std::vector<A> a;

a.push_back(A());
a.push_back(A());

std::for_each(a.begin(), a.end(), std::bind2nd(std::mem_fun_ref(&A::func), 1));
}
0358デフォルトの名無しさんNGNG
こんな簡単なプログラムがコンパイルできません。どこがおかしいのか
わかりますか?コンパイラはgcc3.2.1です。

int main()
{
double ad[] = {0.5, 1.0, 1.5};
std::vector<double> d(ad, ad + 3);

std::transform(d.begin(), d.end(), std::ostream_iterator<double>(std::cout, " "), std::sin);
}
0359デフォルトの名無しさんNGNG
358です。非常に不本意ながら、自己解決しました。
#include <cmath>を#include <math.h>にして、std::sinをsinにすれば通ります。

しかし、ここで当然疑問が沸きます。なぜstd名前空間に包まれているsinが
std::transformに適用できないのか、どうしてもわかりません。何のための
<cmath>なんでしょうか?
0360デフォルトの名無しさんNGNG
>>356-357
compose1 というのは、返値を h = compose1( f, g ) とすると
h(x) が f( g(x) ) と同じ意味になる合成のことなわけだが。
たぶん貴方の場合、std::mem_fun_ref(&A::func) が2変数関数だし、
1 というのは関数ですらないので全然ダメ。

ついでに1変数メンバ関数用の mem_fun_ref は g = mem_fun_ref( f ) とすると
g(x, y) と x.*f(y) が同じ意味になるもので
bind2nd というのは g = bind2nd( f, c ) とすると
g( x ) が f( x, c ) と同じ意味になるものなので期待通りになる。
0361デフォルトの名無しさんNGNG
>>359
C では double sin(double x); しかないが、C++ では
double sin(double x);
float sin(float x);
long double sin(long double x);
とオーバーロードされてて、どれかわからんので困ってるのでは?
0362デフォルトの名無しさんNGNG
>>361
なるほどありがとうございます。キャストしたら通りました。引数が
doubleだからつい自動判別してくれると期待していたのですが、
アルゴリズム中では正しく働かないようですね。

int main()
{
double ad[] = {0.5, 1.0, 1.5};
std::vector<double> d(ad, ad + 3);

std::transform(d.begin(), d.end(), d.begin(), static_cast<double (*)(double)>(std::sin));
}
0363デフォルトの名無しさんNGNG
typedef struct
{
int id;
double value;
} BANK;

std::list<BANK> blist;

みたいなlistがあって、こいつを構造体BANKの中のvalueの値で
sortしたい(valueの値が大きい順に)場合、どうしたらよいのでしょうか?
blist.sort()を使う方を教えてください!!
0364デフォルトの名無しさんNGNG
>>363
sortに引数を渡せ。
0365352NGNG
>>353,354
むむむ、なるほど。情報サンクスコ
なんか大抵の場合はポリモーフィズムかテンプレート使えばいい感じですなぁ・・・
>>853氏の例をちょっといぢってみたんだけど、 6 を 6.0f にするだけで氏ぬのね。
typeid 使うとこの辺(double, float とかポリモーフィズムとか)が問題になって来るわけか。
なるほど、なるほど。勉強になりますた。
0366デフォルトの名無しさんNGNG
>>364
引数の書き方がわからないです。教えてくらはい。
0367デフォルトの名無しさんNGNG
>>366
よーし、SGIのとこからもってきてやったぞ、ホレ。

template<class BinaryPredicate>
void sort(BinaryPredicate comp);

Comp must be a comparison function that induces a strict weak ordering (as defined in the LessThan Comparable requirements on objects of type T.
This function sorts the list *this according to Comp.
The sort is stable, that is, the relative order of equivalent elements is preserved.
All iterators remain valid and continue to point to the same elements.
The number of comparisons is approximately N log N, where N is the list's size.
0368デフォルトの名無しさんNGNG
>>366

struct BANK {
int id;
double value;
BANK(int i, double d) : id(i), value(d) {}
};

inline bool Cmp(BANK a, BANK b)
{
return a.value > b.value;
}

int main()
{
std::list<BANK> blist;

blist.push_back(BANK(1, 1.1));
blist.push_back(BANK(2, 3.3));
blist.push_back(BANK(3, 2.2));

blist.sort(Cmp);

std::list<BANK>::iterator pos = blist.begin();
while (pos != blist.end())
std::cout << pos->id << ", " << pos++->value << std::endl;
}
0369デフォルトの名無しさんNGNG
363、366です。
わかりました!!
これで明日のミーティングに間に合いそうです。
みなさんありがとうございました。
0370デフォルトの名無しさんNGNG
C++のSTLには、叙述関数と関数オブジェクトの2種類があって、互いに
よく似ているために未だに混同します。

例えば関数オブジェクトは内部状態を持っていてそれを変化させても
いいようですが、叙述関数は呼び出しの度に内部状態を変化させては
ならないと規定されているようです。

皆さんはどうやって区別していますか?
0371デフォルトの名無しさんNGNG
370です。(゚Д゚)ハァ?なことを書いてしまってすみません。

叙述関数は、ブール値を返す関数または関数オブジェクトでした。
で、やっぱり関数オブジェクトも内部状態を変化させない方がいいの
でしょうか?
0372デフォルトの名無しさんNGNG
> 呼び出しの度に内部状態を変化させてはならないと規定
これどこで規定されてんの?
0373デフォルトの名無しさんNGNG
>>372
「規定」と書くと語弊がありますね。C++標準ライブラリ日本語版§8.1.4、P297
に「叙述関数と関数オブジェクトの違い」という節があり、内部状態を変化させ
る関数オブジェクトを叙述関数として使うと、予想に反した動作をする例が書か
れています。

つまり、constな関数オブジェクトでないと、予想した動作ではなくなる可能性
があるという事ですね。
0374デフォルトの名無しさんNGNG
>>373
その記述がすべてだな。「可能性がある」ってんだから、
あとは、場合による、としか言えないんじゃないの。
0375デフォルトの名無しさんNGNG
>>374
簡単にまとめると次のようになりますかね。

叙述関数:
  bool値を返す関数または関数オブジェクト。但し、呼び出し毎に内部状態
  が変化する関数または関数オブジェクトは、標準アルゴリズムに適用する
  と予想に反した動きをする可能性があるので、できるだけ使用しない方が良い。
0376デフォルトの名無しさんNGNG
>>375
まとめるのは勝手だが、
「可能性があるので」が理由じゃぁまとまってるとは言い難い。
0377デフォルトの名無しさんNGNG
>>376
やっぱり「可能性」の具体例をあげないとダメか・・・・
本を読んでくれ、なら簡単なんだが、自分でまとめるとなると、何か例を
考えないといけないか。
0378デフォルトの名無しさんNGNG
関数を提供する側から言えば、
副作用がない、と仮定してアルゴリズムが書かれていると、
述語(ここで言えば叙述関数)を呼び出す回数が予想できないわけだ。

副作用がないなら同じ引数で何度呼んでも値は同じはずだから、アルゴリズムは返り値をメモり、以降その値を使いまわすかもしれない。
(しかし副作用がある関数は呼ばれるごとに値が変わることができるから、メモった値と呼んで帰った値は一致しない可能性がある。)
このような性質はアルゴリズム内に隠蔽されていて関数提供側ではまったく予想できない。

一方、逆に標準アルゴリズムを提供する側から言えば、
述語は条件判定に使う関数だから、
例えば副作用がコンテナ内の要素に影響を及ぼす類のものだとすると結果は破壊的になりうるし、そうでなくても同じ対象を比較する際に呼び出すごとに違った値を返すとすると
それらを仮定してアルゴリズムを書くのは大変困難だ。

ひどい例を考えてみる。あるコンテナをソートするとする。
そのときにソートの比較に使う述語(if文の中で比較・判別に使われる)が
大小判定ついでにコンテナの値を書き換えるとすると、
どんなアルゴリズムでも大前提(ソート中に値が変化しない)が崩れるから
ソートはまずまともに機能しないだろう。
(終わらなくなったり、正しくない結果を返したり・・・。)

述語というのは論理学用語だが、
基本的にif文(あるいはfor文など)の条件式内で条件判定に使われる
特殊な種類の関数をさす用語。
普通、if文の中で代入や入出力などするコードはあまりお行儀が良いとは言えない
分かりにくい保守・変更しにくいコードだという事は納得してもらえると思う。それと同じ。
(エラー処理のように条件が成立したら処理を中止するような場合はともかく。)

一方、述語(叙述関数)は関数オブジェクトの中でも特殊なものなので、
一般の関数オブジェクトの在り様まで規制するものではないから、一般の関数オブジェクトは副作用があっても良い。っつーか、むしろないと困るものもあるくらいだろう。
0379デフォルトの名無しさんNGNG
map のコンストラクタで、比較オブジェクトを引数にとるものがあるが、
それの存在意義がわからない。

プログラミング言語C++ 第3版 17.4.1.5
void f(map<string,int>& m)
{
  map<string,int> m2; // デフォルトで < を使う
  map<string,int> m3(m.key_comp()); // mの比較基準を使う
}

とあるが、m.key_comp() は less<string> だから、
デフォルトの < を使うのと同じこと。
比較オブジェクトをコンストラタに渡すのが有意義な場合ってある?
0380デフォルトの名無しさんNGNG
>>379
キーが整数として、比較基準を、ある基準値との差の比較とすると、
比較オブジェクトの中に基準値を入れて使うことが想定できる。

struct compare_distance
{
  const int origin;
  compare_distance(int org):origin(org){}
  bool operator() (int rhs, int lhs) const
  {
    return std::abs(rhs - origin) < std::abs(lhs - origin);
  }
};
0381デフォルトの名無しさんNGNG
>>380 なるほどね。そういう例はわかります。その比較オブジェクトを渡す
mapの型は map<int, T, compare_distance> ですよね。
map<int, T> つまり map<int, T, less<int> > に、渡せるわけではないと。
0382デフォルトの名無しさんNGNG
0383デフォルトの名無しさんNGNG
これこそ型志向言語の神髄中の神髄、C++が最晩年に到達した
何にも真似のできない世界です。このライブラリに込められた
テンプレートの技法は、後世のどの言語もついに超えることが
ありませんでした。ですから現在でもこのライブラリはテンプ
レートの最高の技術を示した作品であり続けています。
C++の晩年には、テンプレートを駆使した手法は時代遅れとなっ
ており、手厳しい非難の対象にもなっていました。しかしC++は
テンプレートを捨てることなく、むしろテンプレートの限界を
極めるような作品を数多く生むようになります。その最高の成
果が、この「Loki」で、たった1つの主題の技法の可能性を徹
底的に汲み尽くした(残念ながらC++の死によって未完となって
いますが)作品となっています。加えて、ソースにコンパイラ
の指定がなく、そのためにVC++版、g++版、Comeau版など、いろ
いろでコンパイラに実装が試されています
0384デフォルトの名無しさんNGNG
>383 バッハの『フーガの技法』の解説のパクリかい?
0385デフォルトの名無しさんNGNG
>384 よく知ってるね
おれの中では両者の間に連想がある。なんというか厳格さと
柔軟さの混在というか...
でももしC++が廃れるようなことがあれば、テンプレートを
魔術的に駆使したものはフーガの技法みたいな扱いを受けそう。
0386デフォルトの名無しさんNGNG
過去の難解言語で為された魔術が
今どういう扱いを受けているか考えてみるといい
0387デフォルトの名無しさんNGNG
最近知ったのですが、boost面白そうですねぇ。
俺の場合、STLとかからちゃんと勉強しないといけないけど(笑)

ところで、boostのfunctionalとかfunctionって、メンバ関数に対しても使えるの??
0388デフォルトの名無しさんNGNG
STLはスレッドセーフですか?そうでないとしたらスレッドセーフなコンテナはありますか?
0389デフォルトの名無しさんNGNG
↑よく知らないけど純粋にテンプレートだけじゃないんですか???
0390デフォルトの名無しさんNGNG
>>388
「このコンテナはスレッドセーフである」と規格に書かれてたりは、しないと思う(たぶん)。実装に依存すると考えるべきではないかなぁ?
0391デフォルトの名無しさんNGNG
Effective STL の Item 12 が "Have realistic expectations about the thread
safety of STL containers." となっているのでこれを読んでみては?
0392デフォルトの名無しさんNGNG
>>387
メンバ関数は第一引数にインスタンスのポインタを
渡してやればいいから、こんな感じ。
#include <iostream>
#include "boost/function.hpp"
#include "boost/bind.hpp"
struct Test {
int t_;
Test(int t) : t_(t) {}
int Add(char t) {return t_ + t;}
};
int main() {
Test test(5);
boost::function1<int, char> func;
func = boost::bind(&Test::Add, &test, _1);
boost::function2<int, Test *, char> func2;
func2 = &Test::Add;
std::cout << (func)(6) << std::endl;
std::cout << (func2)(&test, 6) << std::endl;
}
0393デフォルトの名無しさんNGNG
Boost!

ワル カコイイ(・∀・)!
0394デフォルトの名無しさんNGNG
boost::formatの戻り値をchar*として受け取ってメッセージボックスに
表示したいのですがいい方法は無いですか?
()でくくってc_str()とかやってみましたが、
error C2039: 'c_str' : 'boost::basic_format<Ch,Tr>' のメンバではありません。
[
Ch=char,
Tr=std::char_traits<char>
]
と怒られてしまいます。

MessageBox(NULL, (boost::format("Error !!!\n"
"\tlocation %d:%d\n"
"\tcode %02x:%02x:%02x:%02x\n"
"\tmessage %s\n") %
parse_error->get_line() %
parse_error->get_row() %
parse_error->get_genre() %
parse_error->get_category() %
parse_error->get_sequence() %
parse_error->get_sequence_case() %
parse_error->get_message()).c_str(),
"error", 0);
0395デフォルトの名無しさんNGNG
(...).str().c_str() しかないんでない?
0396393NGNG
SGIには感動した!
精子出た!
ropeキター
0397デフォルトの名無しさんNGNG
Modern C++ Designの19ページの一番下に紹介されてる
「極めて洒落たテクニック」のソースきぼーん
"Sutter"とか"copy constructor"とかで検索したけど
みつからんかった...
0398デフォルトの名無しさんNGNG
>>397
Exceptional C++ の項目13。
0399デフォルトの名無しさんNGNG
>>397
Loki::SmartPtr::operator=()を見たらいいやんって書いてあるやん。
0400デフォルトの名無しさんNGNG
boost使うとコンパイル劇遅で、ノートな私はVCが死んだかと
思ってしまいます。
コンパイルを早くする方法ってないのかな?
templateだからやっぱ無理?
0401デフォルトの名無しさんNGNG
>>400
プリコンパイル
0402デフォルトの名無しさんNGNG
>>401
「プリコンパイルヘッダの使用」とかいうやつ?
0403デフォルトの名無しさんNGNG
gcc-3.6ぐらいにはpchブランチの成果が取り込まれるといいな
0404デフォルトの名無しさんNGNG
>>402
ttp://www1.kcn.ne.jp/~robe/cpphtml/html03/cpp03003.html

この辺が参考になると思う。
■ このスレッドは過去ログ倉庫に格納されています