Таким образом, я не могу использовать инициализаторы в своем конструкторе класса из-за использования массивов, таким образом, я решил использовать 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);
}
Вы можете рассмотреть const_cast
и указатели, но это то, что лучше использовать очень редко. Что-то вроде...
EPWM_REGS** regsPP = const_cast<EPWM_REGS**>(®s);
*regsPP = _regs;
Хотели бы что-нибудь помочь? Вы все еще можете намеренно нарушить константность, но это предохраняет нормальных людей от глупых ошибок (я не скомпилировал это).
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);
};
Как насчет следующего?
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()) {}
};
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>
Используйте такой конструктор:
EPWM::EPWM(volatile EPWM_REGS* _regs)
: regs(_regs)
{}
Тогда просто не оставляйте никаких параметров в init:
void EPWM::init()
{
// do something with this->regs here...
}
Другими словами, вы можете инициализировать все в конструкторе класса - только не массивы-члены.