Ответ 1
Шаблоны С++ хорошо известны для принятия типов в качестве аргументов, но их также можно параметризовать по сравнению с другими типами данных. Например, вы можете templatize класс над целым числом, как показано здесь:
template <typename T, unsigned int N> class Array {
private:
T array[N];
public:
/* ... */
};
Шаблоны также можно параметризовать по указателям, если указатель соответствует определенным критериям (например, он должен оценивать адрес того, что может быть определено во время компиляции). Например, это совершенно легально:
template <int* Pointer> class ThisIsLegal {
public:
void doSomething() {
*Pointer = 137;
}
};
В вашем коде шаблон параметризуется над элементом-указателем. Элемент pointer-to-class похож на указатель на то, что он косвенно относится к некоторому объекту. Однако вместо того, чтобы указывать на объект, вместо этого он указывает на поле в классе. Идея состоит в том, что вы можете разыменовать указатель-класс-член относительно некоторого объекта, чтобы выбрать это поле вне класса. Вот простой пример указателей на класс:
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
, который указывает внутри a 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
, которая при попытке объекта распечатать это поле.
Уф! Это было сложно! Надеюсь, это поможет!