疯狂的C++ template - 用于访问类的各个属性的模板

发布于 2024-11-25 16:50:25 字数 900 浏览 3 评论 0原文

我是一个新手 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++ 专家的解释。我想了解它,以便我可以更好地使用它。不过它看起来非常有用。

I am a novice C++ programmer, but I thought I know enough about C++ until today when I came across code like this at work and failed to understand how it actually works.

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);
}

I think I kind of understood at a high level. But this particular PropType PropObject::* Prop in the template declaration bothers me. What does it mean? I am looking for an explanation from C++ experts. I would like to understand it, so that I can use it better. It looks very useful though.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

皇甫轩 2024-12-02 16:50:25

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 的意思是“a指向 MyStruct 类内的 int 的指针

在您发布的代码中,模板声明如下所示:

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

让我们看看这是什么意思 前两个模板。其属性将要变化的参数对象要读取的属性,以及 PropType,该属性的类型。”模板的最后一个参数是一个名为 Prop 的类成员指针,它指向 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";
}

其中一些内容可以很容易阅读。该函数的参数是对名为 oObject 的引用,最后一行打印出一些字段。这两行很棘手:

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

第一行是一个类型转换,表示“尝试将参数 o 转换为 PropObject 类型的引用。我猜这个想法是,是 Object 是许多不同对象的一些基类。函数的参数只是一个普通的 Object,并且此转换尝试将其转换为某种类型。适当的类型(回想一下 PropObject 是模板参数说明对象的类型是什么),因为这使用了 static_cast,如果未定义转换(例如,您尝试通过 int 实例化模板)。 > 或 vector),代码将无法编译,否则,代码会相信转换是安全的,然后获取 PropObject 类型的引用。 参数指的

最后最后一行

PropType& t = po.*Prop;

是 。使用我之前提到的指向类成员的指针取消引用语法来表示“选择 Prop (模板参数)指向的字段,然后存储对它的引用,名为 t.

简而言之,模板

  1. 会询问您某个对象的类型。
  2. 询问您该对象中某些字段的类型。
  3. 要求您提供指向该对象中字段的指针。
  4. 提供一个 print 函数,给定对象尝试打印该字段。

哇!这很棘手!希望这有帮助!

C++ templates are well-known for taking types as arguments, but they can also be parameterized over other types of data as well. For example, you could templatize a class over an integer, as shown here:

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

public:
    /* ... */
};

Templates can also be parameterized over pointers, as long as the pointer meets certain criteria (for example, it has to evaluate to an address of something that can be determined at compile-time). For example, this is perfectly legal:

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

In your code, the template is parameterized over a pointer-to-class-member. A pointer-to-class-member is similar to a pointer in that it indirectly refers to some object. However, instead of pointing to an object, instead it points to a field in a class. The idea is that you can dereference a pointer-to-class-member relative to some object to select that field out of the class. Here's a simple example of pointers-to-class-member:

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

Notice that the syntax for declaring a pointer-to-class-member is

Type ContainingClass::* pointerName;

So in the above code, int MyStruct::* ptr means "a pointer to an int inside of a MyStruct class.

In the code that you've posted, the template declaration reads like this:

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

Let's see what this means. The first two template argument object whose property is going to be read, and PropType, the type of that property." The final argument to the template is a pointer-to-class-member named Prop that points inside a PropObject at a field of type PropType. For example, you could instantiate this template with MyStruct like this:

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

Now, let's see what the rest of the code does. The body of this class template is reprinted here:

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

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

Some of this can be read pretty easily. The parameter to this function is a reference to an Object named o, and the last line prints out some field. These two lines are tricky:

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

This first line is a typecast that says "try to cast the argument o to a reference of type PropObject. The idea, I'm guessing, is that Object is some base class of a lot of different objects. The parameter to the function is just a plain Object, and this cast tries to convert it to something of the appropriate type (recall that PropObject is the template argument saying what the type of the object is). Because this uses static_cast, if the conversion isn't defined (for example, you tried to instantiate the template over int or vector<string>), the code won't compile. Otherwise, the code trusts that the cast is safe, then gets a reference of type PropObject to what the parameter refers to.

Finally, the last line is

PropType& t = po.*Prop;

This uses the pointer-to-class-member dereference syntax I mentioned earlier to say "select the field pointed at by Prop (the template argument), then store a reference to it named t.

So, in short, the template

  1. Asks you for the type of some object.
  2. Asks you for the type of some field in that object.
  3. Asks you for a pointer to the field in that object.
  4. Provides a print function that given an object tries to print out that field.

Whew! That was tricky! Hope this helps!

乖乖 2024-12-02 16:50:25

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

Declarations in C or C++ are often best read from right to left:

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

This can be seen in action in the instantiations:

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

Here the third template parameter is a pointer to a member of the Student class, that has type int.

不念旧人 2024-12-02 16:50:25

PropObject::* 是一个指向成员(在本例中为数据成员)的指针。它基本上是一个指向(非静态)成员的指针(在您的代码中是 Student::ageStudent::grade)。

要使用它,您必须指定该函数将使用的 this 对象。这是通过使用 .*->* 运算符来完成的;在这种情况下,PropType& t = po.*Prop; 行处理该问题,其中 po 用作成员的 this 对象。

The PropObject::* is a pointer-to-member (data member, in this case). It's basically a pointer to a (non-static) member (which are Student::age and Student::grade in the case of your code).

To use it, you have to specify the this object that the function would use. That's done by using either the .* or ->* operator; in this case, the PropType& t = po.*Prop; line handles that, where po is used as the this object for the members.

朦胧时间 2024-12-02 16:50:25

这是将指针作为参数传递给成员的语法。具体来说,在本例中,可以传入 agegrade 成员。虽然模板参数指定 Student 类,但它是并且成员属性是int

如果您向学生添加了字符串名称,则 PropReader 声明可能如下所示:

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

That's the syntax for passing a pointer to a member as an argument. Specifically in this case it's so that age and grade members can be passed in. While the template args are specifying the Student class it's a member of and that the member properties are int.

If you added a string name to student the PropReader declaration might look like this:

PropReader<Student, std::string, &Student::name> r3;
半衾梦 2024-12-02 16:50:25

但是模板中这个特定的 PropType PropObject::* Prop
声明让我烦恼。这是什么意思?

PropType PropObject::* Prop

这定义了指向类的成员变量的指针,在本例中,类是 PropObject,变量类型是 PropType。

But this particular PropType PropObject::* Prop in template
declaration bothers me. What does it mean?

PropType PropObject::* Prop

This defines pointer that pointing a member variable of a class, in this particular case, the class is PropObject and the variable type is PropType.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文