You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++中如何用结构体常量初始化enum class以表示音符时长?

问题:用enum class表示音符时长的定点数赋值问题

我想用enum class象征性表示音符时长,但枚举仅支持int类型,所以计划用定点数存储,后续通过除法转换为原double值。尝试用结构体存定点常量时,编译器报错“表达式必须是常量值”,因为结构体成员不是编译期常量。代码如下:

const double fp_multiplier = 10000.00; //utility const for fixed point conversion

// fixed point representations of note values
struct {
  const int whole = (int)(1.0*fp_multiplier);
  const int half = (int)(0.5*fp_multiplier);
  const int eigth = (int)(0.125*fp_multiplier);
  const int sixteenth = (int)(0.0625*fp_multiplier);
  const int dotted_eigth = (int)((eigth + 0.5*eigth)*fp_multiplier); 
  const int dotted_sixteenth = (int)((sixteenth + 0.5*sixteenth)*fp_multiplier);
} NoteValues;


enum class NoteValue {
  whole = NoteValues.whole, //not allowed
  half = NoteValues.half,
  eigth = NoteValues.eigth,
  sixteenth = NoteValues.sixteenth,
  dotted_eigth = NoteValues.dotted_eigth,
  dotted_sixteenth = NoteValues.dotted_sixteenth,
};

我知道这是因为NoteValues.whole不是编译期常量(和const关键字无关),想知道怎么用结构体常量给enum class赋值,或者有没有更优的替代方案,必须使用enum class。


可行方案

方案1:用constexpr定义编译期常量(推荐)

把所有需要的常量都用constexpr修饰,确保它们在编译期就能确定值,这样就能直接用于初始化enum class。优先用整数运算处理附点音符,避免浮点精度问题:

constexpr double fp_multiplier = 10000.00;

constexpr int whole_note = static_cast<int>(1.0 * fp_multiplier);
constexpr int half_note = static_cast<int>(0.5 * fp_multiplier);
constexpr int eigth_note = static_cast<int>(0.125 * fp_multiplier);
constexpr int sixteenth_note = static_cast<int>(0.0625 * fp_multiplier);
constexpr int dotted_eigth_note = eigth_note * 3 / 2; // 整数运算更可靠
constexpr int dotted_sixteenth_note = sixteenth_note * 3 / 2;

enum class NoteValue {
  whole = whole_note,
  half = half_note,
  eigth = eigth_note,
  sixteenth = sixteenth_note,
  dotted_eigth = dotted_eigth_note,
  dotted_sixteenth = dotted_sixteenth_note,
};

方案2:用constexpr结构体存储常量

如果想把常量归类到结构体里,需要把结构体成员和实例都声明为constexpr,确保编译期初始化:

constexpr double fp_multiplier = 10000.00;

constexpr struct NoteValues {
  constexpr int whole = static_cast<int>(1.0 * fp_multiplier);
  constexpr int half = static_cast<int>(0.5 * fp_multiplier);
  constexpr int eigth = static_cast<int>(0.125 * fp_multiplier);
  constexpr int sixteenth = static_cast<int>(0.0625 * fp_multiplier);
  constexpr int dotted_eigth = eigth * 3 / 2;
  constexpr int dotted_sixteenth = sixteenth * 3 / 2;
} note_values;

enum class NoteValue {
  whole = note_values.whole,
  half = note_values.half,
  eigth = note_values.eigth,
  sixteenth = note_values.sixteenth,
  dotted_eigth = note_values.dotted_eigth,
  dotted_sixteenth = note_values.dotted_sixteenth,
};

方案3:直接使用计算后的字面量(可读性差,不推荐)

如果不想用constexpr,可以直接把每个定点数的计算结果作为字面量写进enum class,但后续修改乘数时需要重新计算所有值,维护成本高:

enum class NoteValue {
  whole = 10000,
  half = 5000,
  eigth = 1250,
  sixteenth = 625,
  dotted_eigth = 1875,
  dotted_sixteenth = 937
};

补充说明

  • enum class的枚举值必须是编译期常量表达式,普通const变量如果依赖运行时计算,无法用于初始化枚举值。
  • 用整数运算替代浮点运算处理附点音符,既能保证编译期求值,又能避免浮点精度丢失的问题。

内容的提问来源于stack exchange,提问作者Blargian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 22:15:07