2011-07-22 4 views
15

私は初心者のC++プログラマーですが、今日まで仕事に似たコードを見つけ、実際にどのように動作するのか理解できなかった。Crazy C++のテンプレート - クラスの個々の属性にアクセスするためのテンプレート

class Object 
{ 
}; 

template < 
     class PropObject, 
     class PropType, 
     PropType PropObject::* Prop 
     > 
class PropReader 
{ 
public: 
    void print(Object& o) 
    { 
     PropObject& po = static_cast<PropObject &>(o); 
     PropType& t = po.*Prop; 

     cout << t << "\n"; 
    } 
}; 

class Student : public Object 
{ 
public: 
    int age; 
    int grade; 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    Student s; 
    s.age = 10; 
    s.grade = 5; 

    PropReader<Student, int, &Student::age> r; 
    PropReader<Student, int, &Student::grade> r2; 

    r.print(s); 
    r2.print(s); 
} 

私は高レベルで理解していると思います。しかし、テンプレートの宣言のこの特定のPropType PropObject::* Propは私を悩ましています。どういう意味ですか?私はC + +の専門家からの説明を探しています。私はそれを理解したいので、私はそれをより良く使うことができます。それは非常に便利ですね。

答えて

18

C++テンプレートは型を引数として取ることでよく知られていますが、他の型のデータに対してもパラメータ化できます。

template <typename T, unsigned int N> class Array { 
private: 
    T array[N]; 

public: 
    /* ... */ 
}; 

テンプレートはまた、例えば(限り、ポインタが一定の基準を満たしているとして、ポインタを介してパラメータ化することができ、それがアドレスに評価することがあります。ここに示すようにたとえば、あなたは、整数上のクラスをテンプレート化できコンパイル時に決めることのできるもの)。たとえば、これは完全に合法である:あなたのコードで

template <int* Pointer> class ThisIsLegal { 
public: 
    void doSomething() { 
     *Pointer = 137; 
    } 
}; 

、テンプレートはへのポインタ、クラスメンバーオーバーパラメータ化されています。クラスへのポインタは、オブジェクトを間接的に参照する点でポインタに似ています。しかし、オブジェクトを指す代わりに、クラス内のフィールドを指します。そのアイデアは、クラスからそのフィールドを選択するために、あるオブジェクトに関連したクラスへのポインタを参照解除することができるということです。ここでは、ポインタ・ツー・クラス・メンバーの簡単な例です:ポインタ・ツー・クラス・メンバを宣言する構文は、上記のコードでそう

Type ContainingClass::* pointerName; 

int MyStruct::* ptr手段であること

struct MyStruct { 
    int x, y; 
}; 

int main() { 
    MyStruct ms; 
    ms.x = 137; 
    ms.y = 42; 

    int MyStruct::* ptr; // Declare a pointer to a class member. 
    ptr = &MyStruct::x; // Now points to the field 'x' 

    ms.*ptr = 0;   // Set the 'x' field of ms to be zero. 
} 

お知らせ。「あなたが投稿したコードでMyStructクラス

int内部へのポインタは、テンプレート宣言は次のように読み取ります

template < 
    class PropObject, 
    class PropType, 
    PropType PropObject::* Prop 
    > 
class PropReader 

これがどういう意味かを見てみましょう。プロパティを読み込む最初の2つのテンプレート引数オブジェクト、およびそのプロパティの型であるPropType "テンプレートの最後の引数は、という名前のクラスへのポインタで、PropObjectのフィールドを指します。タイプPropTypeたとえば、あなたがこのようなMyStructでこのテンプレートをインスタンス化できます。

PropReader<MyStruct, int, &MyStruct::x> myPropReader; 

さて、残りのコードが何をするか見てみましょう。このクラステンプレートの本体はここに転載されています

void print(Object& o) 
{ 
    PropObject& po = static_cast<PropObject &>(o); 
    PropType& t = po.*Prop; 

    cout << t << "\n"; 
} 

これはかなり簡単に読み取ることができます。この関数への参照は、oという名前のObjectへの参照であり、最後の行はいくつかのフィールドを出力します。これらの2行はトリッキーです:

PropObject& po = static_cast<PropObject &>(o); 
PropType& t = po.*Prop; 

この最初の行は、アイデア「タイプPropObjectの参照に引数oをキャストしようと言って型キャストである私は推測している、Objectは、いくつかの基本クラスであるということです。関数へのパラメータは普通のObjectであり、このキャストはそれを適切な型のものに変換しようとします(PropObjectはオブジェクトの型を示すテンプレート引数です)。これはstatic_castを使用し、変換が定義されていない場合(たとえば、intまたはvector<string>のテンプレートをインスタンス化しようとした場合)、コードはコンパイルされません。 eでは、コードはキャストが安全であることを信頼し、パラメータの参照先のタイプPropObjectの参照を取得します。

最後に、最後の行は

PropType& t = po.*Prop; 

ですこれは、フィールドを選択する「と言って、私は前述のポインタとクラスメンバーの逆参照の構文を使用して店舗、その後、Prop(テンプレート引数)が指しますその参照先はtです。

だから、要するに、テンプレート

  1. は、いくつかのオブジェクトの種類をお願い致します。
  2. そのオブジェクトのいくつかのフィールドのタイプについて問い合わせます。
  3. そのオブジェクトのフィールドへのポインタを要求します。
  4. 与えられたオブジェクトがそのフィールドを印刷しようとすると、print関数を提供します。

Whew!それはやっかいだった!お役に立てれば!

+1

これはすばらしい答えtemplatetypedef ..あなたがそのユーザー名を持っているのも不思議ではありません:) – cgcoder

3

PropObject::*は、メンバへのポインタ(この場合はデータメンバ)です。基本的には、(静的でない)メンバへのポインタです(コードの場合はStudent::ageStudent::grade)。

機能を使用するには、thisオブジェクトを指定する必要があります。これは.*または->*演算子を使用して行います。この場合、PropType& t = po.*Prop;行がそれを処理します。ここでは、poがメンバーのthisオブジェクトとして使用されます。

1

これは、メンバーへのポインタを引数として渡すための構文です。この場合、具体的にはagegradeのメンバーを渡すことができます。テンプレートargsはStudentクラスを指定していますが、メンバーのプロパティはintです。

あなたが学生に文字列名を追加した場合PropReader宣言は次のようになります。

PropReader<Student, std::string, &Student::name> r3; 
0

しかし、この特定のPropType PropObject :: *テンプレート中のプロップ 宣言が私を悩まします。どういう意味ですか?

PropType PropObject::* Prop 

これは、クラスのメンバ変数を指し、この特定の場合では、クラスがPropObjectであり、変数の型はPropTypeあるポインタを定義します。

4

Cでの宣言やC++、多くの場合、最良の右から左に読まれています。

PropType PropObject::* Prop 
         ~~~~ The Prop template parameter 
        ~~~  is a pointer to a member 
     ~~~~~~~~~~   of a PropObject 
~~~~~~~~      where that member has type PropType 

これは、インスタンス内のアクションで見ることができます。

PropReader<Student, int, &Student::age> r; 

ここで第三テンプレートパラメータは、ポインタでありますStudentクラスのメンバには、型がintです。

関連する問題