【问题标题】:C++ new types definition via typedef通过 typedef 定义 C++ 新类型
【发布时间】:2018-02-26 16:08:22
【问题描述】:

我是 C++ 的新手,我遇到了一个问题,我需要在我的类中通过 typedef 定义一个新的数据类型(具体来说是联合)。我班级的.h模块的相关代码sn-p如下

class Manager
{

  public:

    static const uint8_t NO_BYTES_IN_PACKET;
    static const uint8_t NO_PYLD_BYTES_IN_CONTROL_PACKET;

    // control packet structure
    typedef union{
        struct{
            uint8_t header[3];                                
            uint8_t payload[NO_PYLD_BYTES_IN_CONTROL_PACKET];  
        }pkt_parts_t;
        uint8_t pkt_array[NO_BYTES_IN_PACKET];
    }control_pkt_u;

  private:

}

我的问题是常量

static const uint8_t NO_BYTES_IN_PACKET;
static const uint8_t NO_PYLD_BYTES_IN_CONTROL_PACKET;

在相关的 .cpp 模块中定义

const uint8_t Manager::NO_BYTES_IN_PACKET = 8;
const uint8_t Manager::NO_PYLD_BYTES_IN_CONTROL_PACKET = 5;

因此,我在编译过程中收到一条错误消息:错误:数组绑定在 ']' 标记之前不是整数常量。我的想法是将联合定义移动到 .cpp 模块中,但我不确定这是否是正确的方法。你有什么意见?谢谢你的任何想法。

【问题讨论】:

  • aside:typedef union 是一个非常 C 的事情......
  • 在 C 语言中,const uint8_t foo = 5; 不适合作为数组声明的常量。 (例如#define NO_BYTES_IN_PACKET 8
  • 数组大小需要在编译时知道。您需要使用 #define 设置数组大小或将数字文字写入大括号。常量值的运行时评估不起作用。

标签: c++ header-files typedef unions


【解决方案1】:

如果你不odr-use那些static const int,你不需要在.cc文件中定义它们,只需将值放在.h文件中:

class Manager
{

  public:

    static const uint8_t NO_BYTES_IN_PACKET = 8;
    static const uint8_t NO_PYLD_BYTES_IN_CONTROL_PACKET = 5;

/* .... */

};

但是,如果您使用这些常量,例如获取它们的地址,那么您需要在 .cc 文件中定义它们,.h 文件中的类定义保持不变:

const uint8_t Manager::NO_BYTES_IN_PACKET;
const uint8_t Manager::NO_PYLD_BYTES_IN_CONTROL_PACKET;

编辑: 对于声称 static const int 不能用作编译时常量的 cmets 或其他答案,他们的说法是错误的。

以下内容来自[class.static.data]/3(强调我的):

如果一个非易失性 const 静态数据成员是整数或枚举类型,它在类定义中的声明可以指定一个大括号或等式初始化器,其中每个作为赋值表达式的初始化器子句都是一个常量表达式([expr.const])。可以在类定义中使用 constexpr 说明符声明文字类型的静态数据成员;如果是这样,它的声明应指定一个大括号或等式初始化器,其中作为赋值表达式的每个初始化器子句都是一个常量表达式。 [ 注意:在这两种情况下,成员都可能出现在常量表达式中。 — end note ] 如果成员被 odr 使用,则仍应在命名空间范围内定义 ([basic.def.odr]) 和命名空间范围定义中不应包含初始化程序。

【讨论】:

    【解决方案2】:

    问题在于static const 并不意味着它是一个编译时间常数。例如,它不是,它可能是程序启动的时间。

    你想要的是constexpr,它告诉编译器它可以在编译器时计算出来,这意味着你的数组大小已经定义好,并且更清楚地传达了你的意图。

    class Manager{
        public:
            constexpr uint8_t NO_BYTES_IN_PACKET = 8;
            ...
    

    另外;它将迫使您解决真正的问题,即其他编译单元无法看到常量的大小,因为您没有在标题中定义它。

    【讨论】:

    • 感谢您的反应。请你告诉我应该在哪里放置 constexpr uint8_t NO_BYTES_IN_PACKET = 8;和 constexpr uint8_t NO_PYLD_BYTES_IN_CONTROL_PACKET = 5;
    • @Steve 我很确定您应该能够将它们放在您的标题中。我现在没有时间测试和确定。
    • 标题中的确切位置是什么意思?课程范围之外的任何地方?
    • 您的答案不正确。查看答案here
    • 示例不当。变量的值是否可以在编译时确定,并不取决于它何时在标准定义的抽象机中被初始化,因为 as-if 规则。事实上,作为 liliscent 的回答,如果初始化程序在课堂上,一切都很好。更好的解释是这个变量的值在不包含初始化程序的翻译单元中是不可见的(因此无法在编译时确定)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-16
    • 1970-01-01
    • 1970-01-01
    • 2019-12-14
    • 1970-01-01
    • 2015-03-13
    • 1970-01-01
    相关资源
    最近更新 更多