トップページ⇒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 あたりに。
0708デフォルトの名無しさんNGNG
>>707
別に面倒なことなんかないが?
0709703NGNG
すいません.↑意味不明でしたね.
様はtemplateは使わずに,
void f(binary_function<int, int, int> fn);
みたいな感じで使いたいのです.
binary_functionはlessやらplusやらの基底クラスらしいですが,
共通に使われるであろうoperator()を仮想関数として定義
してないんじゃ使えないですね.
引数としてこのクラスの関数オブジェクトを読み込む場合,
この代わりに何を基底クラスとして使うべきなのでしょうか?
0710703NGNG
>>709
templateを使って定義すると,
ソースコードをいちいちincludeしないといけなくなりませんか?
0711デフォルトの名無しさんNGNG
>>709
そんな方法はない。お前はbinary_functionの存在理由を大幅に誤解している。
0712デフォルトの名無しさんNGNG
>>709
そうなると、基底クラスじゃぁないが、boost::functionなんだろうなぁ。
0713デフォルトの名無しさんNGNG
>>709
binary_functionはtypedef導入用のテンプレートであって、
多態で使うことを目的としたものじゃない。

> void f(binary_function<int, int, int> fn);
何故templateにしないでこうしたいのかがよく
わからんが、とりあえず boost::function 使え。
0714703NGNG
>>712
STLじゃ無理なんですね.
0715デフォルトの名無しさんNGNG
>>709
binary_function は引数、戻り値の型を class 内の typedef として定義するための
クラス。それ自身はなんの機能も持たない。

Generic Programming あたりを読んでお勉強するのが良いと思われ。
0716デフォルトの名無しさんNGNG
BCCで、
テンプレート引数の整数はunigned int ではだめで、特別化がおきず、intにしなくてはいけません。
これってC++の仕様ででしょうか?整数引数単独のテンプレはOK。

#include<iostream>
template<class T,unsigned int Sz>
struct vector{
public:
vector(){std::cout << "Standard" <<std::endl;}
};
template<class T>
struct vector<T,3>{
public:
vector(){std::cout << "Special" <<std::endl;}
};

int main(){
vector<double,1> v1;//Standard
vector<double,3> v3;//Specialになってほしいが・・・
return 0;
}
0717デフォルトの名無しさんNGNG
>>716
BCC5.6.2だとちゃんとSpecialになるよ。
0718デフォルトの名無しさんNGNG
>>717
お、そうですか・・・。BCC5.5のバグなんですね。ありがとうございます。
0719デフォルトの名無しさんNGNG

VC++7.0 で、以下の式が正しく通るんだけど…

 // ↓LokiPort for VC++7.0
 Loki::SmartPtrDef<MyClass>::type sp( new MyClass );
 sp[ 2 ];

犯人は特定できたけど、この仕様のおかげで、
自作の添え字演算子を持つポリシーが使えないじゃないかっ!


0720デフォルトの名無しさんNGNG
>>719

音無しくboost::shared_arrayにするよろし
0721デフォルトの名無しさんNGNG
>>719
犯人は?
0722デフォルトの名無しさんNGNG
ヤス
0723デフォルトの名無しさんNGNG
>>722
いつのネタだよ。
ポートピア連即殺人事件の中の人も大変だな。
0724デフォルトの名無しさんNGNG
>>719
operator Tester*()
こいつのおかげで、operator[] が曖昧だといわれてしまう。

>>723
中の人な(ry
0725722NGNG
>>723
通じるなら立派なネタじゃないか
0726デフォルトの名無しさんNGNG
ザクの犯人はシャア
0727デフォルトの名無しさんNGNG
templateの型推測のアルゴリズムが今ひとつわかりにくかったので
良書を探していたら、C++Primerが目に止まった。

この本はC++初心者用だからと今まで目もくれなかったが、今日
何気に立ち止まって読んでみると、templateについてじつに詳しく
書いてある。これだけでも買う価値があると思い、速攻レジへ。

本の厚さに圧倒されつつも、読んでいます。アルゴリズムについて
も相当詳しい解説があります。でもアルゴリズムは一通りやった
んだけどな。
0728724NGNG
>>724 の >>719 へのレスは、>>720 へのレス
0729デフォルトの名無しさんNGNG
treeコンテナ でおすすめなものないでしょうか?
0730デフォルトの名無しさんNGNG
>>729
二分木コンテナ?何に使うの?
0731デフォルトの名無しさんNGNG
>>729
set とか map とか、内部実装的には tree になってるよ。
ちなみに、STL で使われてる平衡木アルゴリズムは二色木(red black tree)。
0732デフォルトの名無しさんNGNG
>>730
バランス木または多分木のコンテナが欲しいです。
ゲームの探索に使おうと思ってます。
0733デフォルトの名無しさんNGNG
>>732
要するに、そのゲームに特化した最適な構造の木を使いたいってこと?
そんな特定用途向けのライブラリ、早々転がってないぞ。

とりあえず、STL ので我慢して作って、
パフォーマンス的にどうしても必要になったら改めて自作しろ。
0734デフォルトの名無しさんNGNG
2つの型が同じかどうか判定することってできるでしょうか

template<typename A, typename B>
bool IsSameType();

いろいろ考えましたが思いつきませんでした・・・
0735デフォルトの名無しさんNGNG
>>731
std::map をどうやって「木として」使うんだ?

>>729
平衡木なら http://www.essemage.com/aapl/ とかが有名どころではなかろうか。
多分木はあんまり見たこと無いなぁ。

>>734
template<typename A, typename B> struct ist { enum{ val = 0 }; };
template<typename A> struct ist<A,A> { enum{ val = 1 }; };

template<typename A, typename B>
bool IsSameType() { return ist<A,B>::val; }
0736デフォルトの名無しさんNGNG
>>729
http://www.damtp.cam.ac.uk/user/kp229/tree/

ってなモノがある。昔boost-mlに流されたけどどーなったんだっけか?
まぁただGPLという最大の罠があるわけだが。
0737デフォルトの名無しさんNGNG
class A1;
class A2;
...

class B {
private:
A1 a1;
A2 a2;
...
public:
};

の時にa1、a2に[]を使ってアクセスする方法はないでしょうか?
0738デフォルトの名無しさんNGNG
#define private public
0739738NGNG
あ、違った。失礼。
まぁ、operator[]でも定義しなさいってこった。
0740737NGNG
A1,A2,・・・がA_Baseから派生していて、a1,a2が配列要素になっていたら
[ ]を定義できるのですが、この場合どうやったらいいか分かりません。
また上記の場合派生して加えた関数にアクセス出来ません。templateを使って旨く出来ないでしょうか?
0741738NGNG
ん?
B::operator[]
をテキトーに定義してやるんじゃマズいの?
なんか良く意味が分かんないんだけど。
0742デフォルトの名無しさんNGNG
>>737
B b; があって、
b[0]がa1、b[1]がa2を返すとか、そういう事かい?
0743737NGNG
switchでべた書きでは無くて何か巧くできないものかと思いまして。
0744737NGNG
>>742 そんな感じです。
B b;
で、b[0].func(hoge) とか出来ない物かと。
0745デフォルトの名無しさんNGNG
>>744
A1とA2が継承関係にでもないと、一つの[]でA1とA2両方返すのは
難しくないかい?
0746デフォルトの名無しさんNGNG
なんかすっきりせんな。

struct A1 {
virtual void func() { std::cout << "A1" << std::endl; }
};

struct A2 : public A1 {
void func() { std::cout << "A2" << std::endl; }
};

struct B {
A1 a1;
A2 a2;
A1* operator[](int i) {
if (i == 0) return &a1;
else return &a2;
}
};

int main()
{
B b;
b[0]->func();
b[1]->func();
}
0747738NGNG
あぁ、そっかそっか。
>>744
で、[]の引数はやっぱコンパイルタイムには決まらんの?
決まるんなら boost::tuple みたいな事すれば
b.get<0>().func(hoge)
なら出来る・・・かな?
0748デフォルトの名無しさんNGNG
friendとtemplateの特殊化を使って実装しようかと試みたが、[]は
メンバ関数でないとだめみたいだしなあ。friend使えたら何とか
なったかもしれんのだが。
0749デフォルトの名無しさんNGNG
だめだこれでも継承関係しか受け付けない。

struct A1 {
virtual void func() { std::cout << "A1" << std::endl; }
};

struct A2 : public A1 {
void func() { std::cout << "A2" << std::endl; }
};

struct B {
A1 a1;
A2 a2;
A1& operator[](int i) {
if (i == 0) return a1;
else return a2;
}
};

int main()
{
B b;
b[0].func();
b[1].func();
}
0750デフォルトの名無しさんNGNG
可能だとしても、そんなオーバーロードは認めたくないね。
0751737NGNG
皆さんありがとうございます。難しいのですね。
>>747 さんの方法も含めて考えてみます。
出来るだけpublicにはしないように頑張っているのですが、初心者には中々難しいです。
0752デフォルトの名無しさんNGNG
struct A1 {
void func() { std::cout << "A1" << std::endl; }
};

struct A2 {
void func() { std::cout << "A2" << std::endl; }
};

struct B {
A1 a1;
A2 a2;
void* operator[](int i) {
if (i == 0) return &a1;
else return &a2;
}
};

int main()
{
B b;
reinterpret_cast<A1*>(b[0])->func();
reinterpret_cast<A2*>(b[1])->func();
}
0753デフォルトの名無しさんNGNG
派生クラスの関数呼び出すんなら、配列(的)にする意味あるの?
0754737NGNG
>>753
B b[100];
としたいので、b[1][1].func(hoge)って呼べた方が楽だなぁと思ったのです。

>>752 ありがとうございます。参考にさせて頂きます。
0755デフォルトの名無しさんNGNG
>>754
> としたいので、b[1][1].func(hoge)って呼べた方が楽だなぁと思ったのです。
激しく読みにくいコードのような気がするが…

面倒でも、素直に「役割」を反映したメソッドを書いて deletate した方が
良いと思うぞ。
0756737NGNG
>>755 そうですか・・・。頑張ってみます。
0757デフォルトの名無しさんNGNG
>>734
> 2つの型が同じかどうか判定することってできるでしょうか
boostの、<boost/type_traits.hpp>をインクルードして、
boost::is_same<T, U>::value
でいけるようだが、中身を見ても何をしているのか解らなかった・・・。
0758729NGNG
>>730-736
結局、色々やるには自分で作った方がいいという結論になったのですが、
上記の物は参考にはなりました。
ありがとうございました。

//構造的にはこんな感じ
template <typename _Elem> class tree
{
tree *parent;
list<tree*> m_child;
_Elem m_element;
};

0759デフォルトの名無しさんNGNG
spirit & phoenix
ホントにキタ━━━━━━(゚∀゚)━━━━━━ !!!!!
0760デフォルトの名無しさんNGNG

スレ違いかもしれんけど、いい知恵を貸してください。

COMなんかで使用する BSTR は ATLインターナル等を読む限り、
「長さをプレフィックスとするOLECHAR型の文字列」だそうです。
 ~~~~~~~~~~~~~~~~~~~~~~~~~~
で、これを std::basic_string で表現したいと思い、
char_traits をいじり始めたのですが、
「長さをプレフィックスとする」の部分で躓きました。

このような長さを先頭にもつ文字列を basic_string で表現する
うまい手段があったら教えてください。
0761デフォルトの名無しさんNGNG
>>760
basic_stringで表現するより、
別のクラスにしてbasic_stringと相互?変換できるようにするほうが楽じゃないの?
0762デフォルトの名無しさんNGNG
760はマルチ
0763デフォルトの名無しさんNGNG
ここでシェルスクリプトのこと聞いてもいいでつか?
それとももっと適した板があるなら教えてくだたい
0764デフォルトの名無しさんNGNG
>>763
シェルスクリプトならUNIX板とかLinux板とかでないかね
0765デフォルトの名無しさんNGNG
>>760
どっちみち、一般のヒープ管理関数じゃなくてSysAllocStringで確保しなきゃいけないわけだし、
プレフィックス部分はポイントされている番地より「前」に存在するわけだし、
いじるならchar_traitsじゃなくてallocatorのほうではないか。
char_traitsはそのままstd::char_traits<wchar_t>でいい気がする。
0766デフォルトの名無しさんNGNG
void wfstream::open
(const char* __s, ios_base::openmode __mod = ios_base::in)

ファイル名が、なぜ wchar_t でなく char なのでしょうか?
0767デフォルトの名無しさんNGNG
VC7で以下が通らないのはVC7のバグ?それとも俺の思い違い?

#include <iostream>
#include <memory>

class A
{
public:
void Print(void){ std::cout << "OK" << std::endl; }
};

int main()
{
std::auto_ptr< A > ptr( new A() );

void (A::*method)(void) = A::Print;
(ptr->*method)(); // ここや

return 0;
}

0768デフォルトの名無しさんNGNG
ptr->* って、std::auto_ptr<A>型についてのメンバ関数へのポインタを
探すことにならんか?
0769デフォルトの名無しさんNGNG
>>767
ptrはA型へのポインタだから、当然Aの中にmethodというメンバ
がないとエラーになる。

struct A {
int i;
}

std::auto_ptr<A> ptr(new A);
int j;
ptr->j;

としているのと極端に言えば同じ。
0770デフォルトの名無しさんNGNG
スマソ>>769は間違いです。見逃してくれ。
0771デフォルトの名無しさんNGNG
A* a;
(a->*method)();

としたら通るね。ということは、std::auto_ptrの->演算子の多重定義
の問題なのだろう。
->の先がメンバー関数へのポインタだった場合、正常に解釈して
くれないのでは。
0772766NGNG
どうか見捨てないで下さい
0773デフォルトの名無しさんNGNG
((*ptr).*method)()
にしれ
0774デフォルトの名無しさんNGNG
>>767
auto_ptr<> には operator->* というメンバ関数はないので
どのコンパイラでも無理だ。
0775デフォルトの名無しさんNGNG
あっそうか!->という演算子ではなくて->*という演算子なのだね。
((*ptr).*method)() が通るという事は、.*は定義されているのかな。
0776デフォルトの名無しさんNGNG
>>775
(*ptr)の時点で A* になってる
0777デフォルトの名無しさんNGNG
あ、ちがうか、A&か。
0778デフォルトの名無しさんNGNG
>>776>>777
なるほどよく理解できました。
そしたら、((*ptr.get()).*method)();が通る理由も理解できます。
0779767NGNG
>>773
神
ってゆーかその手に気付かなかった自分が恥ずかしいよ。
->が定義されてるなら->*も自動だと思ったんだけどそうじゃなかったんだな。
ためしに->*を定義してみたらなかなか面白いことになったけどいまいち使いどころがわかんね。
0780デフォルトの名無しさんNGNG
->* って定義できたっけ?
0781デフォルトの名無しさんNGNG
>>780
できるよ。
0782デフォルトの名無しさんNGNG
でも逆に .* は定義できないんだよね。
->*が定義できるのだから、今度の新しい標準C++はstd::auto_ptrにも
定義して欲しいものだ。
0783デフォルトの名無しさんNGNG
operator->* をユーザー定義して普通の ->* と同じ動作をするものを
作ろうと思ったら、boost::bind 完全再生産、くらいのレベルで大変なんだけど、
なんであんな規格なんだろう。
0784デフォルトの名無しさんNGNG
オーバーロードできない演算子って、
. .* :: ?: sizeof # ##
で全部?
0785デフォルトの名無しさんNGNG
スマートポインタが->*をサポートするには何を返せばいいんだ?
->が返すのは生ポインタだよね。
0786デフォルトの名無しさんNGNG
>>784
typeid
0787デフォルトの名無しさんNGNG
>>785
こんな感じかと

#include <iostream>
#include <functional>

class A
{
public:
int b;
void hoge( int v ){ std::cout << b << v << std::endl; }

public:
template< typename type >
type& operator ->*( type A::*p ){ return this->*p; }
template< typename type >
std::binder1st< std::mem_fun1_t< type, A, int > >
operator ->*( type (A::*p)( int ) ){ return std::bind1st( std::mem_fun1( p ), this ); }
};

int main()
{
A a;
int A::* pb = &A::b;
a->*pb = 10;
void (A::*phoge)( int ) = A::hoge;
(a->*phoge)( 20 );
}
0788デフォルトの名無しさんNGNG
>>784
throw 演算子もできないような気もするが……できるならサンプルプリーズ
0789785NGNG
>>787 にゃるほど。少し分かりました。thx.
0790デフォルトの名無しさんNGNG
>>787
凄すぎ。このコードを理解するように努めてみます。
0791784NGNG
>>786
忘れてました。ども。

そういえば、std::XXX_cast<> 達はキャスト「演算子」なのですかね。
だとしたらオーバーロードできない、でいいと思うけど。

>>788
手元のプログラミング言語C++ 第2版では、throw は演算子じゃなくて式(の一部)のようです。

第3版がほすぃ・・・。
0792デフォルトの名無しさんNGNG
listのeraseで自分のコンテナ以外の反復子を削除できるようなのですが、
この使用は抑止した方がいいのでしょうか?

#include<list>
#include<iostream>
#include<string>
#include<vector>
using namespace std;

int main()
{
list< vector<string> > a,a2;

vector<string > s,s2;
s.push_back("111");
s2.push_back("222");

a.push_back(s);
a2.push_back(s2);

a.erase(a2.begin()); //aのeraseでa2の反復子を削除する。
//list<T>::eraseのソースをみると
//_Mysize--;となっているが、
//_Mysize=size();としないと矛盾しないか?(debbugerのsizeも0,1になってる)

cout << "a size:" << (*(a.begin())).size() << std::endl;
cout << "a2 size:" << (*(a2.begin())).size() << std::endl;//a2の要素は削除されてる
//これはbegin()とend()から計算してるから大丈夫。

cout << "*a.begin():" << *(*(a.begin())).begin() << std::endl;//111
}
0793デフォルトの名無しさんNGNG
>>792
実装的にその方が楽なんよ。
STLは計算効率至上主義だからそういう風になってるんだと思われ。

ほんとはそういうまねは出来ない方がいい。

0794792NGNG
>>793
ちと勘違いしてたんで、修正した。
サイズ等の状態数を管理するのって危険が伴うのにそれを完全に排除してない
方が悪い気がするんだけど。

//上と同じ

int main()
{
list< vector<string> > a,a2;

vector<string > s,s2;
s.push_back("111");
s2.push_back("222");

a.push_back(s);
a2.push_back(s2);

a.erase(a2.begin()); //aのeraseでa2の反復子を削除する。
cout << "aのeraseでa2の先頭の反復子を削除する" << std::endl;

cout << "a.size() :" << a.size() << std::endl; // VC 0 ,GCC 1
cout << "a2.size():" << a2.size() << std::endl; // VC 1 ,GCC 0

cout << "(*a::begin()).size()) :" << (*(a.begin())).size() << std::endl; // VC 1 ,GCC 0
cout << "(*a2::begin()).size()):" << (*(a2.begin())).size() << std::endl; // VC 1 ,GCC 0

cout << "*(*(a.begin())).begin() :" << *(*(a.begin())).begin() << std::endl;//111
//cout << "*(*(a2.begin())).begin():" << *(*(a2.begin())).begin() << std::endl;//
}
0795794NGNG
>>794
よくみたらミスってました...。
cout << "(*a::begin()).size()) :" << (*(a.begin())).size() << std::endl; // VC 1 ,GCC 1
cout << "(*a2::begin()).size()):" << (*(a2.begin())).size() << std::endl; // VC 0 ,GCC 0
であってると思います。
0796デフォルトの名無しさんNGNG
>>794
Sequence::erase の Precondition を破っているので、
未定義動作でしょうがないと思われ。
0797デフォルトの名無しさんNGNG
STLport 使ってて(iostreamは使用せず)
ICU使いたいんですけど
STLportのスタティックライブラリにする必要あります?
経験者の方教えてください。
0798794NGNG
>>796
同じ型のコンテナ内の反復子を矛盾なく削除できる関数として
機能したほうがいいと思うんだけど。
その代わり、多少パフォーマンスは下がってしまうか。

コンテナが反復子の状態数を保存してるときは
反復子を操作(削除)するときに
管理しているコンテナに通知して処理するほうが望ましい結果が得られる。
0799デフォルトの名無しさんNGNG
Boostsを使いたいのですがどこか日本語で詳しく解説してあるサイトか本はありませんか?
あったら教えてください。
0800デフォルトの名無しさんNGNG
>>799
http://user.ecc.u-tokyo.ac.jp/~g940455/wp/boost/index.html
http://www.emaki.minidns.net/Programming/tools/Boost/
http://www.kmonos.net/alang/boost/
0801デフォルトの名無しさんNGNG
Let's boost
ttp://www.kmonos.net/alang/boost/
0802デフォルトの名無しさんNGNG
>>798
iteratorは基本的に自分が属するContainerがどれであるかを知らないし、
Containerは基本的に自分の上のiteratorがどこかに存在しているかどうかを
知らないし、
algorithmは自分が操作する対象がどんなsequenceであるかを知らない…

という形にすることで可能な限り一般性を高める、というのが
STLの方向性だと思うので、↓の是非は別にして、
> コンテナが反復子の状態数を保存してるときは
> 反復子を操作(削除)するときに
> 管理しているコンテナに通知して処理するほうが望ましい結果が得られる。
これはSTLに求める性質としてはお門違いではないかと。
0803799NGNG
>>800 , 801
ありがとうございます。
自分でさがせ、殺すぞ、とか言われるかと思いましたがやさしいですね。
0804794NGNG
>>802
一般的な反復子にはもちろん同意だが、
コンテナ内のtypedef(または定義)されたiteratorを
削除するときは違う。
a.insert(a2.begin()) -> は問題ない
a.erase(a2.begin()) -> a2側に通知が必要

STLの性質を求めてるんじゃなくて、
結果が正しくなることを求めてる。
0805デフォルトの名無しさんNGNG
使い方が間違ってるのに結果が正しくなるのは無理だと思われ
0806デフォルトの名無しさんNGNG
>>804
自分で勝手に自分がどのコンテナオブジェクトに属しているかを知っている
イテレ−タを使ってアクセスされるリストクラスでも作って使っとけアホ。
0807デフォルトの名無しさんNGNG
とりあえず話を>>792に一旦戻すと、
> listのeraseで自分のコンテナ以外の反復子を削除できるようなのですが、
自分のコンテナ以外の反復子を指す要素は削除「できない」。実装によっては
たまたま削除されてしまうかもしれないが、その辺りの動作は未定義。

それをふまえて。

> a.insert(a2.begin()) -> は問題ない
a.insert(a2.begin, value) か? a.erase(a2.begin()) と同じ程度には問題あるだろう。

> 結果が正しくなることを求めてる。
sqrt( "弐" ) とやったら "1.41421356" と返すのが正しい結果だ、
と主張してそれを求めてるのに等しいことは自覚してるか?

無論、sqrt( "弐" ) と同じでコンパイルエラーになるとか、最悪でも
実行時エラーになったら嬉しいのは確かだし、(だからSTLPortの
Debug版とかはかなり重宝されている。) staticメンバ関数を使って
list<T>::erase(a2.begin()) と書けるiterator/container はそれなりに便利だろう。
が、それはSTLの範疇じゃない。
0808807NGNG
×反復子を指す要素
○反復子の指す要素
■ このスレッドは過去ログ倉庫に格納されています