Существует ли метод для именованных экземпляров анонимной структуры для ссылки на функции внутри окружающего класса?
У меня есть класс CRTP, где для ясности API во время рефакторинга я хочу иметь именованную анонимную структуру, содержащую методы, вместо того, чтобы иметь все методы в области класса. Проблема в том, что этим методам нужен доступ к внешней области видимости. Например:
template<typename T>
class sample_class {
public:
struct {
void do_something() {
auto& result = get_ref().something_else(); //get_ref() out of inner struct scope
...
}
} inner;
private:
T& get_ref() { return static_cast<T&>(*this); }
};
Есть ли какая-то техника, чтобы сделать эту работу? В частности, C++14 и gcc7, поскольку я не верю, что анонимные структуры технически совместимы со стандартами.
2 ответа
Класс в другом классе не имеет неявного указателя на указатель this включающего класса.
Если вы хотите, чтобы он имел указатель на экземпляр окружающего класса, явно сохраните его.
struct {
void do_something() {
auto& result = p_sample->get_ref().something_else(); //get_ref() out of inner struct scope
...
}
sample* p_sample;
} inner;
или передать указатель на методы:
void do_something(sample* psample) {
auto& result = p_sample->get_ref().something_else(); //get_ref() out of inner struct scope
...
}
есть способы использовать арифметику указателей для генерации того, что кажется указателем на внешний класс, но они связаны чрезвычайно сложными и опасными правилами C++.
За исключением некоторых правил доступа/именования и т.п., классы, определенные в других классах, не являются магическими. Они могут (теоретически) существовать в других средах; в
inner
может находиться где-то в стеке, а не в
sample
.
Да, вы вычитаете результат
offsetof
из
this
:
auto &self = *reinterpret_cast<sample_class *>(reinterpret_cast<char *>(this) - offsetof(sample_class, inner));
Технически это может быть UB (см. правила доступности дляstd::launder
), но должно быть достаточно хорошим на практике.
Но я утверждаю, что получение красивого имени метода не гарантирует этого хакерства. Просто замените
inner.do_something()
с чем-то вроде
inner_do_something()
.