обойти const в методе init - PullRequest
       4

обойти const в методе init

6 голосов
/ 09 марта 2010

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

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

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

edit: столько, сколько я хотел бы использовать конструктор + инициализатор, который решил бы эту проблему (мой код использовал для этого), я не могу, потому что у меня есть другой класс, имеющий массив Объекты 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);
}

Ответы [ 5 ]

4 голосов
/ 09 марта 2010

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

EPWM_REGS** regsPP = const_cast<EPWM_REGS**>(&regs);
*regsPP = _regs;
1 голос
/ 09 марта 2010

Игра адвокат дьявола: кроме очевидного намерения документации, поскольку это частный атрибут, вы не могли бы совершенно не использовать ключевое слово const и не изменять его отдельно от метода init.

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

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

Хотя, вернитесь к вашему вопросу: хотя массив raw не может быть создан по умолчанию, вы можете написать класс массива, который может быть.

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...

Ладно ... возможно, не так эффективно, как реальный массив ... хотя вы всегда можете обратиться к генерации препроцессора:

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 голос
/ 09 марта 2010

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

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 голос
/ 09 марта 2010

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

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()) {}
};
0 голосов
/ 09 марта 2010

Используйте конструктор, подобный этому:

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

Тогда у init просто нет параметров:

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...