我怀疑这个扩展的存在正是因为没有简单、便携的方法来实现这种行为。您可以使用类似以下的方法来模拟:
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;
}
为了在任何给定的程序中拥有多个这样的结构体,您可以使用匿名命名空间和/或使基础结构体的名称(在此示例中为
param
)成为宏参数,并添加另一个宏
STARTPARAM
(?)来定义该名称的未特化模板。