Шаблоны 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
, которая для данного объекта пытается распечатать это поле.
Уф! Это было сложно! Надеюсь, это поможет!