<?xml version="1.0" encoding="UTF-8" ?><rdf:RDF 
  xmlns="http://purl.org/rss/1.0/"
  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  xmlns:atom="http://www.w3.org/2005/Atom"
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xml:lang="ja">
  <channel rdf:about="http://w.atwiki.jp/stl_japanese/">
    <title>stl_japanese @ ウィキ</title>
    <link>http://w.atwiki.jp/stl_japanese/</link>
    <atom:link href="https://w.atwiki.jp/stl_japanese/rss10.xml" rel="self" type="application/rss+xml" />
    <atom:link rel="hub" href="https://pubsubhubbub.appspot.com" />
    <description>stl_japanese @ ウィキ</description>

    <dc:language>ja</dc:language>
    <dc:date>2006-11-28T01:56:15+09:00</dc:date>
    <utime>1164646575</utime>

    <items>
      <rdf:Seq>
                <rdf:li rdf:resource="https://w.atwiki.jp/stl_japanese/pages/1.html" />
                <rdf:li rdf:resource="https://w.atwiki.jp/stl_japanese/pages/4.html" />
                <rdf:li rdf:resource="https://w.atwiki.jp/stl_japanese/pages/3.html" />
                <rdf:li rdf:resource="https://w.atwiki.jp/stl_japanese/pages/2.html" />
              </rdf:Seq>
    </items>
	
		
    
  </channel>
    <item rdf:about="https://w.atwiki.jp/stl_japanese/pages/1.html">
    <title>トップページ</title>
    <link>https://w.atwiki.jp/stl_japanese/pages/1.html</link>
    <description>
      ＊＊stl_japanese@wikiへようこそ
-stl_japanese@wikiはみんなで気軽に編集できるC++言語標準ライブラリSTLのまとめサイトです。
-このページは自由に編集することができます。


＊＊まずはこちらをご覧ください。
-[[@wikiの基本操作&gt;http://atwiki.jp/guide/category2.html]]
-[[用途別のオススメ機能紹介&gt;http://atwiki.jp/guide/category22.html]]
-[[@wikiの設定/管理&gt;http://atwiki.jp/guide/category6.html]]


＊＊メニュー
-[[STL概要]]
-[[STL入門1]]
-[[STL入門2]]

＊＊バグ・不具合を見つけたら？
お手数ですが、こちらからご連絡宜しくお願いいたします。
⇒http://atwiki.jp/guide/contact.html


＊＊分からないことは？
-[[@wiki ご利用ガイド&gt;http://atwiki.jp/guide/]]
-[[よくある質問&gt;http://atwiki.jp/guide/category1.html]]
-[[@wikiへお問い合わせ&gt;http://atwiki.jp/guide/contact.html]]
等をご活用ください    </description>
    <dc:date>2006-11-28T01:56:15+09:00</dc:date>
    <utime>1164646575</utime>
  </item>
    <item rdf:about="https://w.atwiki.jp/stl_japanese/pages/4.html">
    <title>STL概要</title>
    <link>https://w.atwiki.jp/stl_japanese/pages/4.html</link>
    <description>
      STLとは・・・

STL(Standard Template Library)はC++標準ライブラリの一部です。
STLがC++の標準ライブラリに採用されたのが98年ごろと比較的最近です。        
STLは歴史的経緯からいくつかのバージョンが存在しますがここで扱うのは「標準STL(ANSIのSTL)」です。
現在使用されているコンパイラの一部では正しく動作しないことがありますが、これから発売されるコンパイラは問題ないでしょう。

基本的なコンポーネントはコンテナ・イテレータ・アルゴリズムです。
コンテナとはオブジェクト(データ)を管理する機能を提供するオブジェクトです。
イテレータとはポインタと似たコンテナから提供されるオブジェクト(データ)へのアクセス機能を有するオブジェクトです。
アルゴリズムとはコンテナが提供するイテレータを使用し、ある処理を行う汎用アルゴリズムです。
アルゴリズムはイテレータを介しオブジェクト（データ）を処理することによりコンテナ内部の構造を知る必要がありません。
コンテナはイテレータを提供することにより管理しているオブジェクト（データ）をアルゴリズムへ処理させることが出来ます。
このようにコンテナが期待した特性のイテレータを提供することによりアルゴリズムの恩恵を受けることができます。
また、アルゴリズムはコンテナが提供するイテレータにより汎用性の高いアルゴリズムを提供することができます。

STLを使用するにあたってはC++の文法、特にクラス・継承・オーバーロード・テンプレート・オペレータのオーバーロードなどある程度の知識が必要になります。

最後にSTLは使用することにより劇的に記述するソースの量を減らすことができます。また、スピードアップも期待できます。しかし、使いすぎは禁物です。C++はオブジェクト指向を提供しますがSTLはオブジェクト指向は提供しません。
オブジェクト指向とはまったく別の世界(ジェネリックプログラミング)です。
また、STLを知らない人から見るとまったく理解できないソースになってしまいますので注意が必要です。     </description>
    <dc:date>2006-11-28T01:54:41+09:00</dc:date>
    <utime>1164646481</utime>
  </item>
    <item rdf:about="https://w.atwiki.jp/stl_japanese/pages/3.html">
    <title>STL入門2</title>
    <link>https://w.atwiki.jp/stl_japanese/pages/3.html</link>
    <description>
      *単項関数オブジェクトを使ってみる

STLには関数オブジェクト(もしくはファンクションオブジェクトまたはファンクタ)と呼ばれるコンポーネントが存在します。
STLでは関数オブジェクトはアルゴリズムと共にもっとも作成する機会が多いコンポーネントです。
STLのアルゴリズムには引数に関数オブジェクトを取るものがあり、アルゴリズムの引数に渡す関数オブジェクトによりアルゴリズムを動作を変えることができるのです。
したがって、関数オブジェクトの種類によりアルゴリズムのバリエーションが増えることになります。
関数オブジェクトは基本クラスunary_functionまたは基本クラスbinary_function から継承しoperator()を実装しなければなりません。
パラメータが１つ(単項関数)の場合はunary_functionからパラメータが２つ(二項関数)の場合はbinary_functionからそれぞれ継承します。

----

unary_function基本クラスの定義

template&lt;class _Arg, class _Result&gt;
struct unary_function
{
    typedef _Arg argument_type;
    typedef _Result result_type;
};

----

unary_function・binary_functionはヘッダファイル&lt;functional&gt;に定義されているのでincludeを忘れないでください。
以下に関数オブジェクトのサンプルコードを示します。 

----
例1

 #include &lt;functional&gt;

template &lt;class T&gt;
struct OutputData : public unary_function&lt;T, void&gt;
{
    void operator()(argument_type _t) {
        cout &lt;&lt; _t &lt;&lt; &#039; &#039; ;
    }
}; 


----

関数オブジェクトOutputDataは基本クラスunary_functionから継承し、パラメータはclass Tになります。
基本クラスunary_functionにvoidを渡していますがこれは戻り値が存在しないことを表しています。
ここでは関数オブジェクトOutputDataに戻り値を使用していません。
例１は受け取ったパラメータ_tを標準出力に出力する関数オブジェクトです。

以下に関数オブジェクトOutputDataをアルゴリズムfor_eachに使用したサンプルコードを示します。


----
例２

 #include &lt;functional&gt;
 #include &lt;iostream&gt;
 #include &lt;algorithm&gt;
 #include &lt;vector&gt;

using namespace std;

template &lt;class T&gt;
struct OutputData : public unary_function&lt;T, void&gt;
{
    void operator()(argument_type  _t) {
        cout &lt;&lt; _t &lt;&lt; &#039; &#039; ;
    }
};

int main(int argc, char* argv[])
{
    const int N = 10;
    vector&lt;int&gt; v;

    for (int i = 0; i &lt; N; i++)
        v.push_back(i);

    for_each(v.begin(), v.end(), OutputData&lt;int&gt;() );

    return 0;
} 

----

実行結果
0 1 2 3 4 5 6 7 8 9 

----

for_eachは第一引数から第二引数までの要素に第三引数である関数オブジェクトを適用するアルゴリズムです。
ここでは関数オブジェクトOutputDataを適用しているため全要素が標準出力に出力されます。
例えばアルゴリズムに渡す関数オブジェクトを「受け取った要素」をファイルに保存するような関数オブジェクトを渡すと全要素をファイルに保存してくれることになります。
このように適用する関数オブジェクトによりアルゴリズムのバリエーションが増えることになります。  



*二項関数オブジェクトを使ってみる
      
それでは次にパラメータを２つ取る関数オブジェクト(二項関数オブジェクト)を使ってみましょう。　
二項関数オブジェクトは基本クラスbinary_functionから継承し、operator()を実装します。
以下がbinary_functionの定義です。

----

binary_function基本クラスの定義

template&lt;class _Arg1, class _Arg2, class _Result&gt;
struct binary_function
{
    typedef _Arg1 first_argument_type;
    typedef _Arg2 second_argument_type;
    typedef _Result result_type;
};

----

binary_functionの定義を踏まえてオリジナルの二項関数オブジェクトを作成してみます。


----

例3

template &lt;class T&gt;
struct avgpoint : public binary_function&lt;T, T, T&gt;
{
    result_type operator()(first_argument_type first,
                                   second_argument_type second)
    {
        return (result_type) ((first-second) / 2) + second;
    }
};

----

二項関数オブジェクトavgpointは第一パラメータと第二パラメータの平均を求め戻り値として返しています。
したがって第一、第二、第三の各パラメータは同じclass Tで指定しています。
また、result_type・first_argument_type・second_argument_typeは基本クラスbinary_functionで定義されているのでそのまま使用しています。

それでは独自二項関数オブジェクトavgpointをSTLのアルゴリズムtransformに適用してみます。
アルゴリズムtransformは以下のフォーマットを持ちます。

----

template &lt;class _InIt1, class _InIt2, class _OutIt, class _Fn2&gt;
_OutIt transform(_InIt1 _First1, _InIt1 _Last1,
                   _InIt2 _First2, _OutIt _Dest,
                   _Fn2 _Func)

----

アルゴリズムtransformの第一パラメータと第三パラメータが指し示すイテレータを第五パラメータの関数オブジェクトに渡し、その結果を第四パラメータのイテレータに入れます。
その後、第一・第三・第四パラメータをインクリメントし、第一パラメータが第二パラメータになれば終了します。
関数オブジェクトavgpointをアルゴリズムtransformの第五パラメータへ渡すと第一・第三パラメータの平均値が第四パラメータへ格納されることになります。
以下にサンプルソースを示します。


----
例4

 #include &lt;iostream&gt;
 #include &lt;vector&gt;
 #include &lt;algorithm&gt;
 #include &lt;functional&gt;

using namespace std;

template &lt;class T&gt;
struct  avgpoint : public binary_function&lt;T,T,T&gt;
{
    result_type operator()(first_argument_typefirst,
                                   second_argument_type second)
    {
        return (result_type) ((first-second) / 2) + second;
    }
};

int main(int argc, char* argv[])
{
    vector&lt;double&gt; v1(5), v2(5), v3(5);
    int i;

    v1[0] = 10.0;
    v1[1] = 98.6;
    v1[2] = 12.23;
    v1[3] = 88.8;
    v1[4] = -212.01;

    v2[0] = 2.0;
    v2[1] = 3.3;
    v2[2] = 4.19;
    v2[3] = 155.0;
    v2[4] = -2.0;

    cout &lt;&lt; &quot;Values in v1:?n&quot;;
    for(i=0; i&lt;v1.size(); i++)
        cout &lt;&lt; v1[i] &lt;&lt; &quot; &quot;;
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;Values in v2:?n&quot;;
    for(i=0; i&lt;v2.size(); i++)
        cout &lt;&lt; v2[i] &lt;&lt; &quot; &quot;;
    cout &lt;&lt; endl;

    transform(v1.begin(), v1.end(), 
                  v2.begin(), v3.begin(), 
                  avgpoint&lt;double&gt;());

    cout &lt;&lt; &quot;AVG. : &quot;;
    for(i=0; i&lt;v3.size(); i++)
        cout &lt;&lt; v3[i] &lt;&lt; &quot; &quot;;
    cout &lt;&lt; endl;

    return 0;
}

----

実行結果
Values in v1:
10 98.6 12.23 88.8 -212.01
Values in v2:
2 3.3 4.19 155 -2
AVG. : 6 50.95 8.21 121.9 -107.005

----

実行結果を見るとアルゴリズムtransformの第四パラメータに渡したv3に平均値が格納されていることがわかります。

 

*プリディケート（述語）
    
関数オブジェクトにはプリディケートと呼ばれるものがあります。
プリディケートとはパラメータを１つ以上取り戻り値がbool型の関数オブジェクトです。
プリディケートはアルゴリズムからパラメータを受け取り処理を行います。
その結果をbool型としてアルゴリズムに返し、アルゴリズムはプリディケートから受け取ったbool型を元に処理します。

プリディケートを引数に受け取るアルゴリズムにcount_ifがあります。
以下がサンプルソースです。



----
例5

 #include &lt;functional&gt;
 #include &lt;algorithm&gt;

using namespace std;

template &lt;class T&gt;
struct  count5 : public unary_function&lt;T,bool&gt;
{
    bool operator()(argument_type t)
    {
        return t == 5? true : false;
    }
}; 

int main(int argc, char* argv[])
{
    int iAry[] = { 3, 5, 1, 6, 3, 1 };
    int iNo;
    iNo = count_if( iAry, iAry + 6, count5&lt;int&gt;() );
    printf( &quot;%d?n&quot;, iNo );

    return 0;
} 


----

実行結果
1 

----

プリディケートcount5はアルゴリズムcount_ifからイテレータ経由でパラメータを受け取ります。
プリディケートcount5内では値が5の場合trueを返しているのでアルゴリズムcount_ifはtrueをカウントし戻り値として返しているのです。
その為、実行結果に1が表示されます。     </description>
    <dc:date>2006-11-28T00:56:53+09:00</dc:date>
    <utime>1164643013</utime>
  </item>
    <item rdf:about="https://w.atwiki.jp/stl_japanese/pages/2.html">
    <title>STL入門1</title>
    <link>https://w.atwiki.jp/stl_japanese/pages/2.html</link>
    <description>
      *アルゴリズムを使ってみる

初めに簡単なアルゴリズムのサンプルを示します。
アルゴリズムを使用する場合は記述されているヘッダをinlucdeする必要があります。
ここでは

 #include &lt;algorithm&gt;

を記述してください。
また、STLは全てstdの名前空間に記述されているので事前に

 using namespace std;


を記述するといいでしょう。
使用するアルゴリズムはfillです。
このfillアルゴリズムは指定した範囲に指定した値を充填します。

※コンテナ・イテレータの解説までコンテナは配列・イテレータはポインタで代用しています。
しばらくはコンテナは配列・イテレータはポインタと覚えていても間違いではないでしょう。



----

例１
 #include &lt;algorithm&gt;

 using namespace std;

int main(int argc, char * argv[])
{
    int v[10 ];

    fill(v, v+10, 100 );

    for (int i = 0; i &lt; 10; i++)
        printf(&quot;%d,&quot;, v[i]);

    return 0 ;
}



----

実行結果
100,100,100,100,100,100,100,100,100,100,

----


以下の記述がアルゴリズムを使用している箇所です。    

fill(v, v+10, 100);
    
アルゴリズムfillは第一引数に充填を開始するイテレータ（配列の先頭）を、第二引数に充填を終了するイテレータ（配列末尾の１つ後ろ）を、第三引数に充填する値を渡します。
結果は実行結果をご覧ください。
指定された要素が全て充填されていることがわかります。  
このようにSTLのアルゴリズムはイテレータ(ポインタ)経由でデータに対し、ある処理(アルゴリズム)を適用します。

※STLでは終了を示すイテレータは要素の最後の一つ後ろを指すことが慣例となっています。 
 



*コンテナを使ってみる

次にコンテナを使用してみましょう。
以下に簡単なコンテナのサンプルを示します。
コンテナを使用する場合は記述されているヘッダをinlucdeする必要があります。
ここでは

 #include &lt;vector&gt;

を記述してください。
もちろん

 using namespace std; 

を忘れないでください。
使用するコンテナはvectorです。
これは動的な伸縮可能な配列です。


----

例２

 #include &lt;vector&gt;

 using namespace std;

int main(int argc, char* argv[])
{
    vector&lt;int&gt; v;

    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    v.push_back(5);

    for (int i = 0; i &lt; 5; i++)
        printf(&quot;%d,&quot;,v[i]); 

    return 0;
}

----

実行結果 
1,2,3,4,5,

----

vector&lt;int&gt; v;

がint型のvectorをデフォルトコンストラクタで生成しています。
この時、配列サイズはまだ０です。

v.push_back(1);
～
v.push_back(5);

ではvectorのメンバ関数push_backを使用し要素を終端に追加しています。
要素が追加されると動的に配列サイズが拡張されます。
(この場合、vはサイズ０からサイズ５へ拡張した)  

for (int i = 0; i &lt; 5; i++)
    printf(&quot;%d,&quot;,v[i]); 

で全要素を出力しています。 

このようにSTLのコンテナを使用すれば動的に配列要素数を変更できます。  


*イテレータを使ってみる

イテレータとはコンテナが提供するオブジェクトへのアクセス機能を持ったオブジェクトです。
これまでポインタで代用してきましたがポインタもイテレータと同じ機能を有していますので、
ポインタもイテレータと思って間違いではありません。
しかし、このままですとイテレータとはポインタのことか？となりかねません。
ここでは実際にイテレータを使用してみます。

vector&lt;int&gt; v(10);
vector&lt;int&gt;::iterator ite = v.begin();

上記がイテレータの簡単な作成例です。

vector&lt;int&gt; v(10);

で、配列要素数１０のvectorのvを作成します。

vector&lt;int&gt;::iterator ite = v.begin();

で、iteに配列要素数１０のvectorの先頭を指し示すイテレータを取得しています。
ちなみに

vector&lt;int&gt;::iterator ite2 = v.end();

で、ite2にvの終端を指し示す(終端データの次を指し示す)イテレータを取得しています。
以下にイテレータを使用し配列を充填するサンプルを示します。
ただし、アルゴリズムfillは使用していません。
イテレータ経由でデータを充填しています。


----

例３

 #include &lt;vector&gt;

 using namespace std;

int main(int argc, char* argv[])
{
    vector&lt;int&gt; v(10);

    vector&lt;int&gt;::iterator ite1 = v.begin();

    for (;ite1 != v.end(); ite1++)
        *ite1 = 100;
 
    vector&lt;int &gt;::iterator ite2 = v.begin(); 
    for (; ite2 != v.end(); ite2++)
        printf(&quot;%d,&quot;,*ite2); 

    return 0;
} 


----

実行結果
100,100,100,100,100,100,100,100,100,100,

----

vector&lt;int&gt; v(10);

ここでint型vector配列を要素数１０で構築しています。

vector&lt;int&gt;::iterator ite1 = v.begin();


for (;ite1 != v.end(); ite1++)
    *ite1 = 100;

ここではv.begin()でvectorコンテナの先頭を示すイテレータを取得し、

for (;ite1 != v.end(); ite1++)

で、コンテナの終端までループします。
v.end()はコンテナの終端の要素の一つ次を指し示します(STLの慣例です)のでこれで問題ありません。

 *ite1 = 100;

で、イテレータを介し100を代入しています。
結果として全要素を100で充填していることになります。

これが問題なく動作するのはコンテナが提供するイテレータのoperator++()・oerator*()が
実装されているためです。
そのためポインタをイテレータの代わりに使用しても動作していたのです。
(厳密に言えばポインタとイテレータは違うのですがここでは同じと理解してかまいません)


----

例４

 #include &lt;vector&gt;
 #include &lt;algorithm&gt;

 using namespace std;

int main(int argc, char* argv[])
{
    vector&lt;int&gt; v(10);

    fill(v.begin(),v.end(),100);

    vector&lt;int&gt;::iterator ite2 = v.begin() 
    for (; ite2 ! = v.end(); ite2++)
        printf(&quot;%d,&quot;,*ite2); 

    return 0;
} 

----

実行結果
100,100,100,100,100,100,100,100,100,100,

----

例４は充填にアルゴリズムを使用した例です。
ここまでくれば例１のポインタ版・例４のイテレータ版ともに動作する理由がわかったのではないでしょうか。     </description>
    <dc:date>2006-11-28T00:50:33+09:00</dc:date>
    <utime>1164642633</utime>
  </item>
  </rdf:RDF>
