在 init 方法中绕过 const

发布于 2024-08-24 06:16:40 字数 1169 浏览 7 评论 0原文

因此,由于使用数组,我无法在类构造函数中使用初始值设定项,所以我决定改用 init() 方法。现在我有一个不同的问题。我有一个这样的类:

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

我需要通过初始化 regs = _regs; 来实现 init() 但我不能,因为 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);
}

So I can't use initializers in my class constructor because of using arrays, so I decided to use an init() method instead. Now I have a different problem. I have a class like this:

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

where I need to implement init() by initializing regs = _regs; but I can't because of the const. Is there a way to force the assignment in my init method? I would like to keep the const keyword so I don't accidentally reassign elsewhere.

edit: as much as I would like to use a constructor + initializer, which would solve this problem (my code used to do this), I cannot because I have another class which has an array of EPWM objects, and I can't initialize those objects because C++ does not support initializers for array members. (again, see the other question I asked a little while ago on this subject.)

Context for using EPWM is something like this:

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);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

不念旧人 2024-08-31 06:16:40

您可以考虑 const_cast 和指针,但这是最好的很少使用。非常。像...

EPWM_REGS** regsPP = const_cast<EPWM_REGS**>(®s);
*regsPP = _regs;

You could consider const_cast and pointers, but it's something best used very rarely. Something like...

EPWM_REGS** regsPP = const_cast<EPWM_REGS**>(®s);
*regsPP = _regs;
千紇 2024-08-31 06:16:40

下面的怎么样?

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()) {}
};

How about the following?

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()) {}
};
捶死心动 2024-08-31 06:16:40

这样的事情会有帮助吗?你仍然可以故意违反常量,但它可以防止普通人犯愚蠢的错误(我没有编译这个)。

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);
};

Would something like this help? You can still intentionally violate the constness but it prevents normal people from silly mistakes (I haven't compiled this).

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);
};
时光清浅 2024-08-31 06:16:40

唱反调:除了明显的文档意图之外,由于它是私有属性,您完全可以不使用 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);
};

尽管如此,重新审视你的问题:虽然原始数组不能默认构造,但你可以编写一个可以默认构造的数组类。

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>

Playing devil's advocate: apart from the obvious documentation intent, since it's a private attribute, you could perfectly not use the const keyword and not modify it apart from the init method.

Your const_cast might actually be undefined behavior here, and I certainly prefer not to run in those dark corners, whatever the workarounds.

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

Although, revisit your question: while a raw array cannot be default constructed, you can write an array class that can be.

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... perhaps not as efficient as a real array... you can always turn to Preprocessor generation though:

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>
九八野马 2024-08-31 06:16:40

使用这样的构造函数:

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

然后在 init 中简单地没有参数:

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

换句话说,您可以初始化类构造函数中的所有内容 - 只是不能初始化成员数组。

Use a constructor like this:

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

Then simply have no params in init:

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

In other words, you can initialise everything in the class constructor - just not member arrays.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文