Существует ли метод для именованных экземпляров анонимной структуры для ссылки на функции внутри окружающего класса?

У меня есть класс 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().

Другие вопросы по тегам