16

私は初心者のC++プログラマーですが、仕事でこのようなコードに出くわし、実際にどのように機能するかを理解できなかった今日まで、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++の専門家からの説明を探しています。私はそれを理解したいので、私はそれをよりよく使うことができます。しかし、それは非常に便利に見えます。

4

5 に答える 5

19

C ++テンプレートは、型を引数として取ることがよく知られていますが、他の型のデータに対してもパラメーター化することができます。たとえば、次に示すように、整数を使用してクラスをテンプレート化できます。

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

public:
    /* ... */
};

テンプレートは、ポインターが特定の基準を満たしている限り、ポインターを介してパラメーター化することもできます(たとえば、コンパイル時に決定できる何かのアドレスに評価する必要があります)。たとえば、これは完全に合法です。

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

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

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.
}

クラスメンバーへのポインタを宣言するための構文は次のとおりです。

Type ContainingClass::* pointerName;

したがって、上記のコードでは、「クラス内int MyStruct::* ptrへのポインタ」を意味します。intMyStruct

投稿したコードでは、テンプレート宣言は次のようになっています。

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

これが何を意味するのか見てみましょう。プロパティが読み取られる最初の2つのテンプレート引数オブジェクト、およびそのプロパティのタイプ。 "テンプレートへの最後の引数は、タイプのフィールドでa内を指すPropTypeという名前のクラスメンバーへのポインタです。たとえば、次のようにこのテンプレートをインスタンス化できます。PropPropObjectPropTypeMyStruct

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

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

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

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

これのいくつかはかなり簡単に読むことができます。この関数のパラメーターはObject名前付きのへの参照oであり、最後の行はいくつかのフィールドを出力します。これらの2行は注意が必要です。

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

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

最後に、最後の行は

PropType& t = po.*Prop;

これは、前述のクラスメンバーへのポインター逆参照構文を使用して、「Prop(テンプレート引数)が指すフィールドを選択し、。という名前のフィールドへの参照を格納しますt

つまり、テンプレート

  1. オブジェクトのタイプを尋ねます。
  2. そのオブジェクトのフィールドのタイプを尋ねます。
  3. そのオブジェクトのフィールドへのポインタを要求します。
  4. printオブジェクトを指定してそのフィールドを出力しようとする関数を提供します。

ふぅ!それはトリッキーでした!お役に立てれば!

于 2011-07-22T00:48:27.263 に答える
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ここで、3番目のテンプレートパラメータは、タイプがのクラスのメンバーへのポインタintです。

于 2011-07-22T00:44:24.250 に答える
3

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

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

于 2011-07-22T00:37:44.390 に答える
1

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

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

PropReader<Student, std::string, &Student::name> r3;
于 2011-07-22T00:40:01.957 に答える
0

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

PropType PropObject::* Prop

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

于 2011-07-22T00:41:13.333 に答える