обходя константу в init методе

Таким образом, я не могу использовать инициализаторы в своем конструкторе класса из-за использования массивов, таким образом, я решил использовать init() метод вместо этого. Теперь у меня есть другая проблема. У меня есть класс как это:

class EPWM {
private:
   volatile EPWM_REGS* const regs;
public:
   void init(volatile EPWM_REGS* _regs);
};

где я должен реализовать init() путем инициализации regs = _regs; но я не могу из-за const. Существует ли способ вызвать присвоение в моем init методе? Я хотел бы сохранить const ключевое слово, таким образом, я случайно не повторно присваиваюсь в другом месте.

править: так же, как я хотел бы использовать конструктора + инициализатор, который решит эту проблему (мой код раньше делал это), я не могу, потому что у меня есть другой класс, который имеет массив объектов EPWM, и я не могу инициализировать те объекты, потому что C++ не поддерживает инициализаторы для участников массива. (снова, посмотрите другой вопрос, который я задал только что на этом предмете.)

Контекст для использования EPWM является чем-то вроде этого:

class PwmGroup {
private:
   EPWM *epwm;

   void init(EPWM *_epwm) { epwm = _epwm; }
};

/* ... */
// main code:

EPWM epwm[3];
PwmGroup pwmGroup;

{
   // EPwm1Regs, EPwm2Regs, EPwm3Regs are structs
   // defined by TI's include files for this processor
   epwm[0].init(&EPwm1Regs);
   epwm[1].init(&EPwm2Regs);
   epwm[2].init(&EPwm3Regs);
   pwmGroup.init(epwm);
}

6
задан Community 23 May 2017 в 10:33
поделиться

5 ответов

Вы можете рассмотреть const_cast и указатели, но это то, что лучше использовать очень редко. Что-то вроде...

EPWM_REGS** regsPP = const_cast<EPWM_REGS**>(&regs);
*regsPP = _regs;
4
ответ дан 17 December 2019 в 00:08
поделиться

Хотели бы что-нибудь помочь? Вы все еще можете намеренно нарушить константность, но это предохраняет нормальных людей от глупых ошибок (я не скомпилировал это).

class EPWM {
private:
   volatile EPWM_REGS* regs_for_init_never_use;
   volatile EPWM_REGS* const& regs;
public:
   EPWM() : regs(regs_for_init_never_use)
   void init(volatile EPWM_REGS* _regs);
};
1
ответ дан 17 December 2019 в 00:08
поделиться

Как насчет следующего?

struct EPWM_array {
  EPWM_array() { /* initialize array */ }
  const EPWM *begin() const;
  const EPWM *end() const;

  EPWM array[ 10 ];
};

struct EPWMWrapper {  
   volatile EPWM_REGS* const regs;
   EPWMWrapper(EPWM_array const& a) : regs(a.begin()) {}
};
1
ответ дан 17 December 2019 в 00:08
поделиться

Den Anwalt des Teufels spielen: Abgesehen von der offensichtlichen Dokumentationsabsicht, da es sich um ein privates Attribut handelt, könnten Sie das Schlüsselwort const perfekt nicht verwenden und es nicht außer der Methode init ändern.

Ihre const_cast könnte hier tatsächlich undefiniertes Verhalten sein, und ich ziehe es sicherlich vor, nicht in diesen dunklen Ecken zu laufen, unabhängig von den Problemumgehungen.

class EPWM {
private:
   volatile EPWM_REGS* regs; // normally const, but need to be inited :/
public:
   void init(volatile EPWM_REGS* _regs);
};

Obwohl Sie Ihre Frage noch einmal aufgreifen sollten: Während ein raw-Array nicht standardmäßig erstellt werden kann, können Sie eine Arrayklasse schreiben, die dies tun kann.

namespace detail
{
  template <class T, size_t N, size_t index>
  struct At
  {
    static T& Do(Array<T,N>& array)
    {
      return At<T,N-1,index-1>::Do(array.tail());
    }
  };

  template <class T, size_t N>
  struct At<T,N,0>
  {
    static T& Do(Array<T,N>& array) { return array[0]; }
  };

  template <class T, size_t index>
  struct At<T,0,index> {};

  template <class T>
  struct At<T,0,0> {};
} // namespace detail


template <class T, size_t N>
class array
{
public:
  typedef T value_type;
  static const size_t Length = N;

  array(): mHead(), mTail() {}
  array(const array& rhs): mHead(rhs.mHead), mTail(rhs.mTail) {}

  // Don't know whether it will be optimized or not
  // Not sure I can use pointer arithmetic either :p
  T& operator[](size_t index) { return index == 0 ? mHead : mTail[index-1]; }

  // Compile time access
  template <size_t index>
  T& at() { return detail::At< T, N, index >::Do(*this); }

private:
  T mHead;
  array<T, N-1> mTail;
}; // class array<T,N>

template <class T>
class array<T,1>
{
public:
  typedef T value_type;
  static const size_t Length = 1;

  array(): mHead() {}
  array(const array& rhs): mHead(rhs.mHead) {}

  T& operator[](size_t index) { return mHead; } // or error handling ;)

private:
  T mHead;
}; // class array<T,1>

template <class T> class array<T,0> {}; // int[0] does not work (stack) so...

Okay... vielleicht nicht so effizient wie ein echtes Array... Sie können sich jedoch immer an die Präprozessorgenerierung wenden:

template <class T>
class Array4
{
public:
  Array4(): m0(), m1(), m2(), m3() {}
  Array4(const Array4& rhs): m0(rhs.m0), m1(rhs.m1), m2(rhs.m2), m3(rhs.m3) {}

  T& operator[](size_t index) { return *(&m0 + index); }

private:
  T m0;
  T m1;
  T m2;
  T m3;
}; // class Array4<T>
1
ответ дан 17 December 2019 в 00:08
поделиться

Используйте такой конструктор:

EPWM::EPWM(volatile EPWM_REGS* _regs)
    : regs(_regs)
{}

Тогда просто не оставляйте никаких параметров в init:

void EPWM::init()
{
    // do something with this->regs here...
}

Другими словами, вы можете инициализировать все в конструкторе класса - только не массивы-члены.

0
ответ дан 17 December 2019 в 00:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: