深く浅く分析するC++trits技術

9572 ワード

前言
tritsは、特性抽出技術とも言われています。簡単に言えば、「伝達されたオブジェクト」に対応する返却タイプを抽出して、同じインターフェースに対応する機能を実現させることです。STLのアルゴリズムとコンテナは分離されているので、両者はローズマリーでリンクされています。アルゴリズムの実現は、自分が何を伝えられているかを知らない。抽出器は、インターフェースと実装の間にパッケージを追加することに相当し、いくつかの詳細を隠し、適切な方法の呼び出しを支援する。これはいくつかの技術(例えば、偏特化)が必要である。最後に小さな例が付いています。特性抽出をよりよく理解できるはずです。
以下の大部分は『STLソース解析』に由来しています。原書を読むと、より多くの詳細が分かります。
Traitsプログラミング技法
問題を少しずつ投げて、少しずつ深く入りましょう。
1.まず、アルゴリズムの中でローズマリーを使うと、その該当するパターンが使われる可能性が高いです。アルゴリズムで変数を宣言する必要があると仮定しますが、「サブコマンダーの指す対象の型别」を型别としてどうすればいいですか?
解決方法は、function templateを利用したパラメータ導出メカニズムです。

template <class I, class T>
void func_impl(I iter, T t) {
        T tmp; //                   
        // ...     
}

template <class I>
inline
void func(I iter) {
        func_impl(iter, *iter); //   iter iter    ,class    
}

int main() {
    int i;
    func(&i);
}
ここではすでにパッケージの意味が分かります。implのパッケージがないと、その都度表示されます。パッケージを重ねたらすっきりします。
ローズマリー対応の型は「ディエゼルの指す対象の型别」だけではありません。経験によると、最も一般的な対応型は5種類ありますが、いずれも上記のtemplateパラメータ導出機構を利用して取得することができます。
関数の「templateパラメータ導出機構」で導出されたのはパラメータだけで、関数の戻り値の種類は導出できません。関数の回送値を導き出す必要があったら、どうすることもできません。
2.インサイダー宣言はいいアイデアのようです。直接に入手できます。

template <class T>
struct MyIter {
    typedef T value_type; //       
    // ...
};

template <class I>
typename I::value_type
func(I ite) {
    return *ite;
}

// ...
MyIter<int> ite(new int(8));
cout << func(ite);
見た目はいいですが、すべてのサブマシンがクラスタイプというわけではありません。class typeでないと埋め込み型を定義できません。
この時は特化が必要です。
3.偏った特化とは特化に加えて制限を加えることであるが、特化したtemplateである。

 template <class I>
  struct iterator_traits {
      typedef typename I::value_type value_type;
  };
  
  template <class I>
  struct iterator_traits<T*> {
      typedef T value_type;
  };
 
 template <class I>12 typename iterator_traits<I>::value_type
 func(I ite) {
     return *ite;
 }
FncはIを呼び出す時、まずIを抽出器に伝えて、抽出器は最適なvalue_にマッチします。タイプ抽出器はまず特別なバージョンにマッチします。このように原生の指針を伝えた時に、まずマッチするのは「T*」の偏った特化バージョンです。このようにvalue_typeはTで、事前に声明していないI:value_タイプ。このように値を返すとtypename iterator_が使えます。trits:value_typeは戻りのタイプを知っています。
以下に「STLソース解析」の画像を添付します。

トラストにもっと多くのことをさせます。
ローズマリーはよくある5種類のタイプがあります。value_タイプライタータイプライタータイプライターtypeはtritsと対応する偏向特化から抽出しやすいです。でも、iteratorcategoryは普通は5つもあります。これによって、大きな規模のコード作成工程が発生します。
例えば、func_を実現しました。II,func_BI,func_RAIは、それぞれ、サブエージェントタイプを表しています。Input Iterator、Bidirectional Iterator、Random Access Iteratorの対応が実現されます。
今、お客様がフルnc()を呼び出す時、判断が必要かもしれません。

template<class Iterator>
void func(Iterator& i) {
    if (is_random_access_iterator(i))
        func_RAI(i);
    if (is_bidirectional_iterator(i))
        func_BI(i);
    else
        func_II(i);
}
このように実行時期にどのバージョンを使うかが決定されると、プログラムの効率に影響を与えます。コンパイル期間に正確なバージョンを選択したほうがいいです。
この関数機構を再負荷するとこの目標が達成できる。

struct input_iterator_tag {};
 struct output_iterator_tag {};
struct forward_iterator_tag : public input_iterator_tag {};
 // ...
 //        ,       input_iterator_tag    
//        forward_iterator_tag,        ,      
いくつかの列を声明したら、func関数を再搭載できます。
ここまでは、各型式の具体的な積載が完了しましたが、統一されたインターフェースが必要です。この時、トレーツは出場できます。

template<class Iterator>
 inline void func(Iterator& i)
 {
    typedef typename Iterator_traits<Iterator>::iterator_category category;
    __func(i, category()); //       
 }
単純なインスタンスコード
だから、tritsは一方で、異なる入力クラスに直面する時、適切なリターンパターンを見つけることができます。一方、パターン別対応が異なる実装関数がある場合は、パターンを抽出して分岐する役割を果たすことができる。
まず、func関数があると仮定して、カスタマイズされたクラスやオリジナルのポインタをパラメータとして受け入れて、自動的に出力して何を使っていますか?
まずtritsに従って、uの戻りパターンを抽出し、対応する構造関数return_を呼び出します。type()は、各重載バージョン_u u ufuncの重負荷フラグは、異なる実際の関数を区別します。

まず、インタフェースコードの作成を見ます。

 template <class unknown_class>
 inline typename unknown_class_traits<unknown_class>::return_type //          
 func(unknown_class u) {
     typedef typename unknown_class_traits<unknown_class>::return_type return_type;
     return __func(u, return_type()); //          tag
 }
そして設定を実現します。前述のIIやRAIなどを真似します。

 template <class unknown_class>
 inline typename unknown_class_traits<unknown_class>::return_type
 return_type(unknown_class) {
     typedef typename unknown_class_traits<unknown_class>::return_type RT;
     return RT();
 }
これらがあればテストできます。

struct A {};
struct B : A{};
そしてtritsが堂々と登場し、2つの偏った特化版があります。

/*     */
template <class unknown_class>
struct unknown_class_traits {
    typedef typename unknown_class::return_type return_type;
};

/*      ――       */
template <class T>
struct unknown_class_traits<T*> {
    typedef T return_type;
};

/*      ――       */
template <class T>
struct unknown_class_traits<const T*> {
    typedef const T return_type;
};
急に交代を忘れました。unknown_。クラスの構造、カスタムクラスは、typedefが必要です。

 template <class AorB>
struct unknown_class {
   typedef AorB return_type;
};
最後はfuncそれぞれのリロードバージョンです。

template <class unknown_class>
inline typename unknown_class_traits<unknown_class>::return_type
__func(unknown_class, A) {
    cout << "use A flag" << endl;
    return A();
}

template <class unknown_class>
inline typename unknown_class_traits<unknown_class>::return_type
__func(unknown_class, B) {
    cout << "use B flag" << endl;
    return B();
}

template <class unknown_class, class T>
T
__func(unknown_class, T) {
    cout << "use origin ptr" << endl;
    return T();
}
これらがあればテストできます。

int main() {
    unknown_class<B> b;
    unknown_class<A> a;
    //unknown_class<int> i;
    int value = 1;
    int *p = &value;

    A v1 = func(a);
    B v2 = func(b);
    int v3 = func(p);

    char ch = getchar();
}
カスタムクラスで同じインターフェースに入ると、対応する関数が自動的に使用され、戻り値も適切であることが分かります。オリジナルの針にも適用されています。完璧です。

付属する
以下は完全コードです。

#include <iostream>
using namespace std;

/*     tag*/
struct A {};
struct B : A{}; //        ,        A,
                //         B   ,             

/*        */
template <class AorB>
struct unknown_class {
    typedef AorB return_type;
};

/*     */
template <class unknown_class>
struct unknown_class_traits {
    typedef typename unknown_class::return_type return_type;
};

/*      ――       */
template <class T>
struct unknown_class_traits<T*> {
    typedef T return_type;
};

/*      ――       */
template <class T>
struct unknown_class_traits<const T*> {
    typedef const T return_type;
};


/*         */
template <class unknown_class>
inline typename unknown_class_traits<unknown_class>::return_type
return_type(unknown_class) {
    typedef typename unknown_class_traits<unknown_class>::return_type RT;
    return RT();
}

template <class unknown_class>
inline typename unknown_class_traits<unknown_class>::return_type
__func(unknown_class, A) {
    cout << "use A flag" << endl;
    return A();
}

template <class unknown_class>
inline typename unknown_class_traits<unknown_class>::return_type
__func(unknown_class, B) {
    cout << "use B flag" << endl;
    return B();
}

template <class unknown_class, class T>
T
__func(unknown_class, T) {
    cout << "use origin ptr" << endl;
    return T();
}

template <class unknown_class>
inline typename unknown_class_traits<unknown_class>::return_type
func(unknown_class u) {
    typedef typename unknown_class_traits<unknown_class>::return_type return_type;
    return __func(u, return_type());
}

int main() {
    unknown_class<B> b;
    unknown_class<A> a;
    //unknown_class<int> i;
    int value = 1;
    int *p = &value;

    A v1 = func(a);
    B v2 = func(b);
    int v3 = func(p);

    char ch = getchar();
}
結尾語
特性抽出に時間がかかりましたが、プログラムが飛び出した瞬間はとても楽しかったです。
まず、侯捷先生に感謝します。先生の本はこんなにはっきりと説明しています。
これを見たら画像のフーリエ変換が見られます。あはは。
以上はC++trits技術についての簡単な話です。C+trits技術に関する資料は他の関連記事に注目してください。