TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.37K subscribers
Post #922 4.57K
​​pointer to data member
#опытным

В этом посте мы рассказывали о том, что с помощью ranges и и параметра проекции можно кастомизировать алгоритмы с соответствии с определенным полем класса. Например, чтобы найти в коллекции элемент с максимальным определенным полем, то можно сделать так:

struct Payment {
double amount;
std::string category;
};
auto max = *std::ranges::max_element(payments, {}, &Payment::amount);


max в этом случае будет транзакцией с максимальным размером платежа.

В последней строчке используется &Payment::amount - указатель на поле amount в классе Payment. Но если это параметр функции, то это значение какого-то типа. Но какой тип у этого указателя?

Если про указатели на конкретные мемберы знают не только лишь все, то это совсем дебри плюсов.

Явный тип указателя на поле класса используется так:

struct Payment {
double amount;
std::string category;
};

double Payment::*ptr = &Payment::amount; // Here!

Payment payment{3.14, "Groceries"};
std::cout << payment.*ptr << std::endl;
// OUTPUT:
// 3.14


double Payment::*       ptr         = &Payment::amount;
// тип указателя имя указателя инициализатор


По сути это особый тип указателя, который хранит смещение поля относительно начала объекта в байтах. Это не специфицировано в стандарте, но примерно везде так работает.

Мы обязательно должны указать, на какой тип полей этот указатель может указывать. Таким образом указатель ptr может указывать на любое поле класса Payment, имеющее тип double. То есть:

struct Type {
int a;
int b;
float c;
};

int Type::*p = nullptr;

p = &Type::a; // OK, a is int
p = &Type::b; // OK, b is int

p = &Type::c; // ERROR! c is float


Указателю на интовое поле нельзя присвоить указатель на флотовое. И наоборот, указатель p работает с любыми полями типа int.

Если вы подумали, что очень узкоспециализированная вещь, то вы правы. Чуть больше универсализации здесь могут дать шаблоны:

// Takes pointer to any data member for any type
template<typename T, typename FieldType>
void print_field(const T& obj, FieldType T::*field) {
std::cout << obj.*field << std::endl;
}

Payment payment{3.14, "Groceries"};
Type t(42, 69, 3.14);

print_field(payment, &Payment::amount);
print_field(payment, &Payment::category);

print_field(t, &Type::a);
print_field(t, &Type::b);
print_field(t, &Type::c);
// OUTPUT
// 3.14
// Groceries
// 42
// 69
// 3.14


print_field может печатать значение любого поля любого класса по его указателю. Обратите внимание на шаблонную сигнатуру.

Walk through the nooks and crannies. Stay cool.

#cppcore #memory
  • ❤ 26
  • 🔥 15
  • 👍 11
  • 🤯 1
More from @grokaemcpp
  1. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  2. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  3. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  4. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
  5. Sep 28, 2026​​Stacktrace #опытным Одна из проблема исключений - непонятно, откуда оно прилетело. Ну да…
  6. Sep 25, 2026​​std::spanstream #опытным Радостная весть для всех, кто пользуется iostreams! В C++23 доб…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →