Чтобы ответить на точный вопрос, есть, но это довольно сложно, и это будет просто во время компиляции. (Если вам нужен поиск во время выполнения, используйте указатель на член - и, основываясь на обновленном вопросе, возможно, вы неправильно поняли, как они работают.)
Во-первых, вам нужно что-то, что вы можете использовать для представления "имени члена" во время компиляции. В метапрограммировании во время компиляции все, кроме целых чисел, должно быть представлено типами. Таким образом, вы будете использовать тип для представления члена.
Например, член типа integer, в котором хранится возраст человека, а другой - для хранения его фамилии:
struct age { typedef int value_type; };
struct last_name { typedef std::string value_type; };
Тогда вам нужно что-то вроде map
, которое выполняет поиск во время компиляции. Давайте назовем это ctmap
. Давайте поддержим до 8 участников. Во-первых, нам нужен заполнитель для представления отсутствия поля:
struct none { struct value_type {}; };
Тогда мы можем заранее объявить форму ctmap
:
template <
class T0 = none, class T1 = none,
class T2 = none, class T3 = none,
class T4 = none, class T5 = none,
class T6 = none, class T7 = none
>
struct ctmap;
Затем мы специализируем это для случая, когда нет полей:
template <>
struct ctmap<
none, none, none, none,
none, none, none, none
>
{
void operator[](const int &) {};
};
Причина этого станет ясна (возможно) через мгновение. Наконец, определение для всех остальных случаев:
template <
class T0, class T1, class T2, class T3,
class T4, class T5, class T6, class T7
>
struct ctmap : public ctmap<T1, T2, T3, T4, T5, T6, T7, none>
{
typedef ctmap<T1, T2, T3, T4, T5, T6, T7, none> base_type;
using base_type::operator[];
typename T0::value_type storage;
typename T0::value_type &operator[](const T0 &c)
{ return storage; }
};
Что, черт возьми, здесь происходит? Если поставить:
ctmap<last_name, age> person;
C ++ создаст тип для person
путем рекурсивного расширения шаблонов, потому что ctmap
наследует от себя , и мы предоставляем хранилище для первого поля, а затем отбрасываем его при наследовании. Все это внезапно прекращается, когда больше нет полей, потому что начинается специализация для всех - none
.
Итак, мы можем сказать:
person[last_name()] = "Smith";
person[age()] = 104;
Это похоже на поиск в map
, но во время компиляции с использованием класса именования полей в качестве ключа.
Это означает, что мы также можем сделать это:
template <class TMember>
void print_member(ctmap<last_name, age> &person)
{
std::cout << person[TMember()] << std::endl;
}
Это функция, которая печатает значение одного элемента, где элемент для печати является параметром типа. Таким образом, мы можем назвать это так:
print_member<age>(person);
Так что да, вы можете написать что-то вроде struct
, немного похоже на время компиляции map
.