Deducting this в C++23
В C++23 завезут Deducting this. Если коротко, то это возможность указать this как явный параметр метода класса, при этом тип этого параметра может быть шаблоном.
Основное применение Deducting this - это устранение дублирующегося кода для одинаковых методов с разными cv-qualifiers (const/volatile) и ref-qualifiers (&, &&).
Например у нас есть следующий код на C++ 20, который идиоматически правильно определяет все варианты доступа к одной из своих переменных:
class my_class {
public:
int & data() & { return data_; }
const int & data() const & { return data_; }
int && data() && { return std::move(data_); }
private:
int data_;
};
С помощью Deducting this мы сможем заменить три одинаковых варианта функции data
одним:
class my_class {
public:
auto && data(this auto && self) {
return std::forward<decltype(self)>(self).data_;
}
private:
int data_;
};
У Deducting this есть ещё несколько применений, но лично для себя считаю важным возможность замены громоздкого кода CTPR (Curiously Recurring Template Pattern) на Deducting this.
CTPR - это способ реализации полиморфизма через наследование, аналогичный виртуальным функциям, но только времени компиляции, а не исполнения.
Например, у нас есть базовый класс base
, в котором есть метод foo
. Мы хотим сделать так, чтобы метод foo
вызывал метод bar
, определённый в классах-наследниках, но без динамического диспатчинга. Т. е. мы не планируем вызывать метод foo
у переменной типа base
с неизвестным во время компиляции конкретным типом. Метод foo
будет вызываться всегда только у переменной, имеющий тип класса-наследника, известный во время компиляции. Сделать это можно так:
template <typename Derived>
class base {
public:
void foo() {
static_cast<Derived*>(this)->bar();
}
};
class derived: public base<derived> {
public:
void bar() {
// ...
}
};
// где-то дальше в коде
derived d;
d.foo();
Такой подход используется уже десятилетиями, но выглядит довольно убого. После добавления Deducting this больше не потребуется городить шаблоны и использовать static_cast
:
class base {
public:
void foo(this auto && self) {
self.bar();
}
};
class derived {
public:
void bar() {
// ...
}
};
У Deducting this есть ещё несколько разных применений: передача this по значению, использование в лямбдах, исправление мелких проблем при overload resolution.
Ссылка на Proposal: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0847r7.html
comments powered by Disqus