我正在寻找一种存储小型多维数据集的方法,这些数据在编译时已知且永远不会更改。此结构的目的是充当全局常量,存储在单个命名空间中,但在没有实例化对象的情况下可以全局访问。
如果我们只需要一级数据,有许多方法可以做到这一点。您可以使用带有静态/常量变量的枚举
或类
或结构体
:
class MidiEventTypes{
public:
static const char NOTE_OFF = 8;
static const char NOTE_ON = 9;
static const char KEY_AFTERTOUCH = 10;
static const char CONTROL_CHANGE = 11;
static const char PROGRAM_CHANGE = 12;
static const char CHANNEL_AFTERTOUCH = 13;
static const char PITCH_WHEEL_CHANGE = 14;
};
我们可以使用这个类及其成员变量在程序的任何地方轻松比较数值变量:
char nTestValue = 8;
if(nTestValue == MidiEventTypes::NOTE_OFF){} // do something...
但是如果我们想要存储的不仅仅是名称和值对呢?如果我们还想要每个常量都存储一些额外的数据怎么办?在上面的例子中,假设我们还想要存储每种事件类型需要读取的字节数。
以下是一些伪代码用法:
char nTestValue = 8;
if(nTestValue == MidiEventTypes::NOTE_OFF){
std::cout << "We now need to read " << MidiEventTypes::NOTE_OFF::NUM_BYTES << " more bytes...." << std::endl;
}
我们还应该能够像这样做:
char nTestValue = 8;
// Get the number of read bytes required for a MIDI event with a type equal to the value of nTestValue.
char nBytesNeeded = MidiEventTypes::[nTestValue]::NUM_BYTES;
或者另外一种选择:
char nTestValue = 8;
char nBytesNeeded = MidiEventTypes::GetRequiredBytesByEventType(nTestValue);
而且:
char nBytesNeeded = MidiEventTypes::GetRequiredBytesByEventType(NOTE_OFF);
这个问题不是关于如何让已实例化的类做到这一点。我已经可以做到了。这个问题是关于如何存储和访问与常量相关/附加的“额外”常量(不变数据)。 (这个结构在运行时不是必需的!)或者如何创建多维常量。似乎可以使用静态类来完成这个任务,但是我已经尝试过以下代码的几个变体,每次编译器都会找到不同的问题:
static class MidiEventTypes{
public:
static const char NOTE_OFF = 8;
static const char NOTE_ON = 9;
static const char KEY_AFTERTOUCH = 10; // Contains Key Data
static const char CONTROL_CHANGE = 11; // Also: Channel Mode Messages, when special controller ID is used.
static const char PROGRAM_CHANGE = 12;
static const char CHANNEL_AFTERTOUCH = 13;
static const char PITCH_WHEEL_CHANGE = 14;
// Store the number of bytes required to be read for each event type.
static std::unordered_map<char, char> BytesRequired = {
{MidiEventTypes::NOTE_OFF,2},
{MidiEventTypes::NOTE_ON,2},
{MidiEventTypes::KEY_AFTERTOUCH,2},
{MidiEventTypes::CONTROL_CHANGE,2},
{MidiEventTypes::PROGRAM_CHANGE,1},
{MidiEventTypes::CHANNEL_AFTERTOUCH,1},
{MidiEventTypes::PITCH_WHEEL_CHANGE,2},
};
static char GetBytesRequired(char Type){
return MidiEventTypes::BytesRequired.at(Type);
}
};
这个特定例子不起作用,因为它不允许我创建一个static unordered_map
。如果我不将unordered_map
设为static
,那么它可以编译,但是GetBytesRequired()
无法找到map。如果我将GetBytesRequired()
设为非静态,则可以找到该映射,但是我不能在没有MidiEventTypes
实例的情况下调用它,而且我也不想要它的实例。
再次强调,这个问题不是关于如何修复编译错误的,而是关于存储静态/常量数据的适当结构和设计模式,其中数据不仅限于键/值对。
以下是目标:
数据和大小在编译时已知,并且永远不会更改。
使用人类可读的键访问一小组数据,每个集合都应映射到一个特定的、非线性整数。
每个数据集包含相同的成员数据集。即每个
MidiEventType
都有一个NumBytes
属性。可以使用命名键或函数访问子项。
使用键(或代表键值的变量),我们应该能够读取与键指向的常量项相关联的额外数据,使用另一个命名键来读取。
我们不需要实例化类来读取此数据,因为没有任何更改,并且不应有多个数据集的副本。
实际上,除了include指令之外,不需要其他内容来访问数据,因为它应该像常量一样行为。
我们不需要在运行时使用此对象。目标是通过存储具有命名标签结构的数据组,而不是在各处使用(模糊的)整数文字,使代码更有组织性和易于阅读。
它是一个可以深入挖掘的常量...就像JSON一样。
理想情况下,不需要进行强制转换即可使用常量的值。
我们应该避免重复列表,以避免重复数据且可能不同步。例如,一旦我们定义了
NOTE_ON = 9
,则文字9
不应出现在任何其他地方。应使用标签NOTE_ON
,以便只需在一个地方更改该值。这是一个通用问题,MIDI只是一个示例。
常量应该能够具有多个属性。
最佳的方法是什么,用于存储已知在编译时大小固定、具有层次结构(多维)的静态数据集合,并具有与常量相同的用例?
constexpr
键中查找属性。你需要你所描绘的运行时查找吗?还是你实际上总是使用字面常量键(例如NOTE_ON
)? - Useless