TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.37K subscribers
Post #656 4.28K
Deducing this
#опытным

Все методы принимают неявный параметр - указатель this на текущий объект. Также мы можем вызывать методы для объектов с разной константностью/ссылочностью. И главное - компилятор знает в момент компиляции вызова метода настоящий тип объекта со всеми квалификаторами. Единственное, что отделяется нас от возможности введения шаблонности - это указательный тип this, который не инкапсулирует в себе информацию о квалификаторах объекта.

И в С++23 именно этот момент и изменили. Теперь мы можем явно указывать тип объекта, на который указывает this. И это по сути полностью заменяет cv и ref квалификацию методов. Выглядит это так:

struct cat {
std::string name;

void print_name(this cat& self) {
std::cout << name; //invalid
std::cout << this->name; //also invalid
std::cout << self.name; //all good
}
void print_name(this const cat& self) {
std::cout << self.name;
}
void print_name(this cat&& self) {
std::cout << self.name;
}
void print_name(this const cat&& self) {
std::cout << self.name;
}
};


Особенности:

👉🏿 Мы явно указываем параметр this.

👉🏿 Явно указываем тип объекта и его квалификаторы.

👉🏿 Считайте, что это статические методы, внутрь которых передали объект того же класса. Синтаксис доступа в полям соотвествующий: нельзя упоминать this, нельзя неявно обращаться к членам класса, только через имя параметра.

👉🏿 Поэтому нельзя такие методы объявлять статическими, ибо невозможно будет различить вызов статического и нестатического метода с одинаковым именем.

Теперь у нас есть все инструменты и мы можем сделать шаблонный this. Давайте посмотрим на обновленный метод value класса optional:

template <typename T>
struct optional {
// One version of value which works for everything
template <class Self>
constexpr auto&& value(this Self&& self) {
if (self.has_value()) {
return std::forward<Self>(self).m_value;
}
throw bad_optional_access();
}
};


Вот это бэнгер! Мы деквадруплицировали код!

Здесь мы используем шаблонный параметр Self с универсальной ссылкой. В этом случае параметр self будет в точности повторять тип объекта, на котором вызван метод. И для правильной передачи значения наружу мы используем идеальную передачу и std::forward + auto&& возвращаемое значение, которое тоже будет соответствовать cv+ref типу объекта.

Настоящая магия, причем вне хогвартса!

Имена Self и self использовать необязательно, это отсылки к питону и первом параметру методов классов self.

Вот вам пропоузал по этой замечательной фиче. А мы в нескольких следующих постах будем разбирать кейсы, где она может быть применима.

Simplify your life. Stay cool.

#cpp23 #template
  • 🔥 37
  • ❤ 9
  • 👍 8
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 →