初始化枚举索引数组?

时间:2011-11-17 12:29:29

标签: c++ arrays gcc enums g++

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和内存繁重的东西?

3 个答案:

答案 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文件中定义枚举和“外部值”。