gcc在C中有一个非常好的扩展,它允许你使用枚举作为键将数据保存在数组中:
enum keys
{
key_alpha = 0,
key_beta = 1,
key_gamma = 2
};
ValType values =
{
[ key_alpha ] = { 0x03b1,"alpha" },
[ key_gamma ] = { 0x03b3,"gamma" },
[ key_beta ] = { 0x03b2,"beta" }
};
这很好,因为如果列表必须更改,添加或删除行不会破坏赋值,很明显哪个键对应于哪个值,并且导致简单代码与普通标准数组初始化没有区别。 / p>
不幸的是,这个扩展在g ++中不可用。
在C ++中做同样事情的首选轻量级方法是什么?优选地,不基于< map>的东西。以及那些使用字符串键,隐藏索引,繁重模板或其他CPU和内存繁重的东西?
答案 0 :(得分:14)
#include <iostream>
#define KEYS_DEF \
KEY_DEF( alpha, 0x03b1, "alpha" ), \
KEY_DEF( beta, 0x03b2, "beta" ), \
KEY_DEF( gamma, 0x03b3, "gamma" )
#define KEY_DEF( identifier, id, name ) identifier
enum keys { KEYS_DEF };
#undef KEY_DEF
#define KEY_DEF( identifier, id, name ) { id, name }
struct ValType { int id; char const* name; };
ValType const values[] = { KEYS_DEF };
int main()
{
using namespace std;
for( int i = alpha; i <= gamma; ++i )
{
cout << values[i].name << endl;
}
}
干杯&amp;第h。,
答案 1 :(得分:4)
我怀疑这种扩展是否存在正是因为没有简单,可移植的方法来实现这种行为。您可以使用以下内容来模拟它:
enum keys
{
key_alpha = 0,
key_beta = 1,
key_gamma = 2
};
struct ValType {
int v;
const char *name;
};
template <int key>
struct param;
#define SETPARAM(key,value1,value2) \
template <> \
struct param< (key) > { \
static constexpr ValType t {(value1),(value2)}; \
}
SETPARAM(key_alpha, 0x03b1,"alpha");
SETPARAM(key_gamma, 0x03b3,"gamma");
SETPARAM(key_beta, 0x03b2,"beta");
便携式,符合您的要求,而不是特别“重型模板”。
如果你没有使用C ++ 11,你仍然可以这样做,专门用于param
模板的宏会变得稍微长一些。
使用int i = someinput(); cout << param<i>::t.name;
合法的修改:
#include <cassert>
enum keys
{
key_alpha = 0,
key_beta = 1,
key_gamma = 2
};
struct ValType {
int v;
const char *name;
};
template <int key>
struct param {
enum { defined = false };
static constexpr ValType t {0, 0};
};
template <int key>
constexpr ValType param<key>::t;
static const int MAXPARAM=255;
#define SETPARAM(key,value1,value2) \
template <> \
struct param< (key) > { \
static_assert(key <= MAXPARAM, "key too big"); \
enum { defined = true }; \
static constexpr ValType t {(value1),(value2)}; \
}; \
constexpr ValType param<(key)>::t
template <int C=0>
struct get_helper {
static const ValType& get(int i) {
return i==0 ? (check(), param<C>::t) : get_helper<C+1>::get(i-1);
}
private:
static void check() {
assert(param<C>::defined);
}
};
template <>
struct get_helper<MAXPARAM> {
static const ValType& get(int) {
assert(false);
}
};
const ValType& GETPARAM(int key) {
return get_helper<>::get(key);
}
诀窍是实例化get_helper
并使用可用于断言索引有效性的标志来递归调用。如果需要,您可以增加MAXPARAM
,但它会使编译速度变慢。
示例用法非常简单:
#include "enumidx.hh"
#include <iostream>
SETPARAM(key_alpha, 0x03b1,"alpha");
SETPARAM(key_gamma, 0x03b3,"gamma");
SETPARAM(key_beta, 0x03b2,"beta");
int main() {
int key = key_beta;
const ValType& v = GETPARAM(key);
std::cout << v.name << std::endl;
}
要在任何给定的程序中使用多个这些,您可以使用匿名命名空间和/或使基本struct
(在此示例中为param
)的名称为宏参数并添加另一个宏STARTPARAM
(?)定义该名称的非专用模板。
答案 2 :(得分:2)
廉价,偷偷摸摸,欺骗性的解决方案:在所有.cpp文件旁边的单独的.c文件中定义“值”变量,在.h文件中定义枚举和“外部值”。