Форвард объявить защиту typedef - PullRequest
0 голосов
/ 23 мая 2018

Я пытаюсь переслать объявление некоторых переменных, используемых только в классе для ограничения количества заголовков, которые я должен включить при использовании этого.

К сожалению, класс, который я хочу переслать, имеетОказалось, что это typedef, и это сторонняя библиотека, которую я не могу редактировать (давайте назовем ее «boost :: asio :: strand» ради аргумента)

Этот вопрос Впередобъявление typedef в C ++ Демонстрирует, что единственными решениями являются:

  • Просто включите заголовок и примите, что это невозможно
  • Перейдите вперед, объявите, что будет typedef'ed идобавить свой собственный typedef

Глядя на второе решение, есть ли способ защитить себя от изменения typedef в библиотеке, чтобы компилятор жаловался на typedef, а не на использование неопределенноготипа, когда класс удаляется / переименовывается и делает его меньше головной боли обслуживания?

1 Ответ

0 голосов
/ 23 мая 2018

Я бы постарался вообще не полагаться на предварительное объявление исходного класса.Возможно, я пропустил случай, но я думаю, что предварительное объявление полезно только для чисто частного использования, если тип каким-то образом появляется в сигнатуре метода или если ваш класс содержит член, который каким-то образом указывает или ссылается на тип, возможно косвенно.

Я предлагаю перенаправить объявление обертки для класса и определить его только в файле реализации, когда фактический класс или typedef известны.

Скажем, ваш заголовок класса в настоящее время выглядит следующим образом:

// need header because it contains UglyTypeDef:
#include <UglyHeader.h>

class MyClass {
public:
  int theMethod(int a);
private:
  void uglyMethod(UglyTypeDef &utd);

  int someMember;
  UglyTypeDef *utdp;
  std::vector<UglyTypeDef *> utds;
};

В этом примере мы могли бы сделать с предварительным объявлением, но мы не хотим полагаться на внутренние компоненты UglyHeader.

Я бы изменил MyClass следующим образом:

class MyClass {
public:
  int theMethod(int a);
private:
  // move the private method into the implementation file   

  // hide the ugly typedef
  // we safely forward declare our own private wrapper
  struct UglyTypeDefWrapper;

  int someMember;
  UglyTypeDefWrapper *utdp;
  std::vector<UglyTypeDefWrapper *> utds;
};

Теперь, чтобы заставить это работать, реализация в файле cpp также должна измениться:

#include "MyClass.hpp"
#include <UglyHeader.h>

struct MyClass::UglyTypeDefWrapper {
   // if possible save another level of indirection 
   // and store by value, otherwise use a second indirection
   // by cleverly wrapping at the right level of abstraction 
   // this abstraction can be free in many cases
   UglyTypeDef td;
};

namespace {
  // we completely hide the private method in this file as
  // an implementation detail and pass it whatever it needs
  // this also helps the compiler to inline it, 
  // because it knows it cannot be referenced in 
  // a different compilation unit
  // we need to pass all members as needed
  void uglyFormerMethod(int &someMember, UglyTypeDef &utd) {
    someMember += utd.whatever();
  }
}

int MyClass::theMethod(int a) {
  utd->td.doWhatever();
  uglyFormerMethod(someMember, *utd);
  for(auto utdwp: utds) {
    utdwp->td.doIt();
  }
}
...