トップページ
ひらく | たたむ | ページトップ
↓マウスで反転選択した文字を検索
C++
   
ページ内検索 ページ外検索
検索したい文字を入力して
ENTERを押すと移動します。
\n
[ トップページ ]
[ ____CommandPrompt ] [ ____JScript ] [ ____MySQL ] [ ____Cygwin ] [ ____Java ] [ ____Emacs ] [ ____Make ] [ ____Perl ] [ ____Python ] [ ____OpenGL ] [ ____C# ] [ ____StyleSheet ] [ ____C++ ] [ ____Winsock ] [ ____Thread ] [ ____VisualStudio ] [ ____C ] [ ____Win32API ] [ ____Lua ] [ ____PhotoShop ]
ヘッダ検索

___

■ テンプレート(Template)


___

■ Template する場所を見抜く方法

[ 処理が同じ ]で [ Data 型が異なる ]ところ. -> 逆に関数とは, 特定の処理をひとくくりにすること. Instanciate した時点で既に, template ではないことに注目. 次のような記述もえきる。
     struct Tbl
     {
       string name;
       void *(*create)();
     }; 

    Tbl tbl[] = {
      {
        {"Chara", create<  Chara > }, 
      }
値を交換する処理は、型が違うだけで処理は同じ。 オーバーロードした瞬間にテンプレートが利用できないか考えること。 コンパイラにやらせてしまう。
    int swap( int &a, int &b ) {
      int t = a;
      a = b;
      b = t;
    }

    float swap( float &a, float &b ) {
      float t = a;
      a = b;
      b = t;
    }
型をパラメータ化して関数のテンプレートをつくる。
    template < typename T>
    void swap( T& a, T& b )
    {
        T t = a; 
        a = b; 
        b = t;
    }  

    swap(x, y);      // コンパイラが自動で生成する。
    swap< int>(x, y); // 型を明示する場合は int をつける。
___

■ 関数テンプレート(FunctionTemplate)

SYNTAX [ class | typename ] keyword 利用する。 template < class type> function-declarator template < typename type> function-declarator template < class X1 , class X2> void println(X1 var1 , X2 var2); 関数テンプレートには2種類の場所で定義できる。
     グローバル関数
     メンバ関数
// template 型であることの宣言 template< class T > T myabs( T a ){ a = a>0 ? a : -a; } // 使用するときは
  int b = -7;
  int n = myabs( b );

  // 明示する
  int b = -7;
  int n = myabs< int>( b );
PrmTpl が返値のみでも OK. -> ただしどの型に対して Instanciate するべきか教える必要がある. -> 関数の後に < >() とあったら, PrmTpl を 明示していると考えよう. template < typename T > T foo() { T data = 0; return data; } Client::main() { int i = func< int>(); } WARNING 引数が複数ある場合は、同一の型がくるとしても template 名を分ける必要あり
    template<  class T1, class T2 >
    T1 Add( T1 a, T2 b ){
      return a+b;
    }  

      int a = 5;
      char b = 3;
      int n = add( a, b );

___

■ クラステンプレート(ClassTemplate)

DESC 意味としては、クッキーの型だと思えばOK 素材( 型 )と処理を分離して考える 内部的な型だけを変換していると思えばOK , あくまでクラス定義しているにすぎない 次のように考えるとわかりやすい template< XXX > を除去 2. XXX -> 具体的な型に変換 [ vector ] を例に考えてみる.
      vector<  myInt > foo;   // int 型 vec ( 使用する際は, < 型> とする )
      
      template < T> 
      class vector{
         T foo;
      }
// 変換後( こう見ればよい ) class vector{ int foo; } // 使用する際は vector< int > aaa; // [ int型 vector クラスの aaa を生成した ] と考える
___

■ 型だけでなく 値もパラメータとして受け取れる

非型パラメータを指定する場合は型名は実際の型にする。

    // 固定サイズの配列
    template < typename T, int N>
    class Array {
      public:
        void push_back( const T &data ) {
          data[ p ] = data;
          p ++;
        }

        Array() : p(0){}

      private:
        T data[N];
        int p;
     };
使うときは非型パラメータの部分は値を指定する。
    // int 型 10 要素の固定配列
    Array< int, 10> a;
    a.push_back( 5 );
整数型・列挙型の値 オブジェクトへのポインタ・参照 関数へのポインタ・参照 メンバへのポインタ POINT template の型を固定することもできる
//
// unsigned にすることで,負数を避けることが可能. 

// アラインメントをそろえる
      template<  unsigned int BASE, typename T >  
      T floor( T x ) 
      {
        return static_cast< T>( ((x) + ((BASE)-1)) & ~((BASE)-1) );
      }

    // 利用する時は
    roundUp< 16>( 10 );
___

■ テンプレートパラメータにデフォルト値を設定する

デフォルト値を指定するには、デフォルト引数と同様に = TYPE とする。 STL クラスはアロケータのデフォルトとして std::allocator< T> をもつ。
      template < class T, class Allocator = allocator< T> >
      class vector
      {
        ...
      }

そのため利用するときは、要素型を指定するだけでよい
    vector<  int > v;
自作のアロケータがある場合は、指定することでメモリ処理をカスタマイズできる。
    class MyAllocator {

    };

    vector<  int, MyAllocator > v;
___

■ template 化するコンパイラの立場で考えてみる

template < class T> // 以下は汎用クラスだよ. ( 未知の型がくるよ. とりあえず T にするよ ) template < [typelist] [ , [ arglist]] > declaration パラメータ化した汎用関数、または汎用クラスだよー と compiler に通知. declaration : 関数またはクラスを宣言 typename nameType 未知の識別子の[ 型 ]だよ- とコンパイラに通知( class keyword でも OK )
___

■ 特殊化する

DESC ある特定のテンプレート型の場合だけ特別仕様にする時につかう。 特定の template 引数用に定義すること. -> 特殊化する前に、汎用 template を定義する必要あり XXX 型の場合の特別バージョンという意味。
    template< >   
    void func<  XXX >{} 
特化するには, 汎用のテンプレート( 定義 | 宣言 )が必要になる。
           // 基本は CMP 単位で処理されて, 

           // あ !  foo という FunctionTemplate があるな... 
           template <  typename T > T foo();

           // これは float 型の場合に利用する関数だな...
           template < > 
           float foo< float>()
           {
             float data = 0.0f;
             printf("special");
             return data;
           }            

           Client::main() {
              // foo はたしか, FunctionTemplate で float 型の特殊定義があったな... 
              // よし今回はこれを使おう. 
              foo<  float >();
           }
引数の数は合わせる必要があるらしい. 宣言のみ && 特化の場合は CMP は通るが, LINK で落ちる. ie. 特化は別 Module でしてもいいことになる. -> 要は, FunctionTemplate の宣言は, パラメータ数のみが一致すれば CMP OK な汎用宣言だと考えよう.
       template < typename T>
       void copy(T* dst, const T* src, size_t size)
       {
         for(size_t i = 0; i <  size; i++) {
           dst[i] = src[i];
         }
       }
// 特殊化( 型を指定しない -> < > , 逆に template< > とある場合は, template 本体がある. ) // XXX の場合と言い換えよう template < > void copy< char>(char* dst, const char* src, size_t size) { memcpy(dst, src, size); } template < > static inline ErrorCode DEPRECATED createInterface( pad **unknown, uint32_t no) { return interfacebase::impl::createInterfaceImpl(unknown, no); } // 部分特殊化 // 元となるテンプレート template < typename T1, typename T2, int I> class A { ... }; // 部分特殊化したもの template < typename T, int I> class A< T, T*, I> { ... }; template < typename T1, typename T2, int I> class A< T1*, T2, I> { ... }; template < typename T> class A< int, T*, 5> { ... };
___

■ template 全般

Class, 関数の定義をパラメータ化する ( Java にない便利機能 ) 定義を抽象化( Grouping )する. 通常は. 宣言と定義を header にする。 宣言のみでは LINK できない。 コンパイル時にコードを生成するため、コンパイル単位で定義が必要になるため。 基本的に define 同様の置換がされるが, PreProcessor ではなくコンパイラがコードを生成する 汎用 class( 型 )だけでなく, 固定型も使用可能. = をつけると Default 設定. ( = とでてきたら Default で [い.く.つ] と考えること ) 実際に使用して == ( PrmTpl )を与えて, 評価されるらしい.
   //  MethodTemplate も作成できる
      class Foo {
       public:
        template<  typename T >
        void func( T i ) 
        {
         cout < <  i < <  endl;
        }
      }; 
      
      foo.func( 10.0f );
      foo.func( 10 );
      foo.func( "10" );
FunctionTemplate と 通常関数が 同名ならば, 通常関数が優先される. -> ただし TypeCheck して固定関数にあうものがなければ, FunctionTemplate から生成されるよ. template< typename T > void func( T i ) { cout < < i < < endl; } // 固定関数. void func( int i ) { cout < < "fixfunc " < < i < < endl; } { unsigned int i = 10; func( i ); // FunctionTemplate がよばれる. } 前方宣言も OK bCls が ClassTemplate の場合, bCls の変数はクラスを明示しないとアクセスできない. ( 言語仕様. GCC は準拠. VS++ では無視. )
     class Object {
        // ctor という Method を template 化した
        template<  typename T >
        Object( T ty ){ ... }  
     };

     int i;     
     Object o( i );
template < class T, int N = 1> // Default 1 && Arg2 は int であると CMP に通知. class Allocator { } -> FuncTemplate には利用できないらしい. ( なんで ? ) Template 内容に矛盾があれば, コンパイル時にエラーがおきる
       // SmartPtr を 実装.
       class Resource
       {
   public:
     void use(){ /*参照カウンタ+1*/ }
     void release(){ /*参照カウンタ-1と解放*/ }
       };

       template < class T>
       class SmartPointer
       {
   T *m_pointer;   // 本体.
        public:
   // INIT
   SmartPointer(T *p)
     :m_pointer(p) {
   {
       // 置換した状態で矛盾があれば CmpErr
       m_pointer->use();
   }

   ~SmartPointer() {
     m_pointer->release();
   }
       }
___

■ template 具体例

DESC setter, getter の template 化 // prop object template < class T> // 以下は汎用クラスだよ. ( 未知の型がくるよ. とりあえず T という名前にするよ ^/ ) class typeProp : public absProp { public: virtual eProp getType() const; // accessor という処理は同じ. vitual T getVal( base *p ) = 0; vitual void setVal( base *p, T val ) = 0; };
___

■ 色々実験してみる

Q: PrmTpl を引数にとらない関数は FuncTemplate にできるか ? template< typename T > void func() { T i = 20; printf( i ); } func< int>(); // OK: 文として矛盾が起きないなら問題なし. func(); // ERR: TemplateParamter がわからない. < T > と教えてあげる. func< Foo >(); // ERR: ここで本当に instantiated しているらしい. Foo i = 20; // ERR func(); // ERROR: no matching function for call to `func()' func が具体化されていいない証拠.
___

■ refcnt : 参照カウンタ

DESC object 自身が他から, 参照される個数をカウントする. 0 になれば, 不要ということで解放. -> new した時点で 1. POINT 2. create() 作成 && release() 破棄 3. Model から参照されている際に、削除できないようにリソースという扱いにしている ( ie. new, delete < -> create(), release() なんだ ) 4. mdl->release() は mdl というポインタ( 矢印 )から Object(Resource)を離すイメージ // delete のかわり、[ 参.照.し.な.い.よ ] と宣言. virtual void release(){ counter --; if ( counter == 0 ){ delete this; } } // これを呼ばないとだめなのが, メンドイ. void use(){ counter ++; } // 作成時に cnt = 1 Resource() : m_counter(1), m_name(0) { } WARNING obj が相互に 参照する場合は, 循環がおき, mem leak がおきるので注意 任意の数値を文字列に変換する関数テンプレート。
    #include < iostream>
    #include < string>
    #include < sstream>

    template< class T> 
    string numberToString(T n)
    {
        stringstream s;
        s < <  n;

        return ss.str();
    }


NINJAIDX 12