Шаблоны 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
означает «указатель на int
внутри класса MyStruct
.
В опубликованном вами коде объявление шаблона выглядит так:
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";
}
Кое-что из этого можно прочитать довольно легко. Параметр этой функции является ссылкой на Object
с именем o
, а последняя строка выводит какое-то поле. Эти две строки сложны:
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
.
Итак, вкратце, шаблон
- Запрашивает у вас тип некоторого объекта.
- Запрашивает тип некоторого поля в этом объекте.
- Запрашивает указатель на поле в этом объекте.
- Предоставляет функцию
print
, которая при заданном объекте пытается распечатать это поле.
Вау! Это было сложно! Надеюсь это поможет!
person
templatetypedef
schedule
22.07.2011