好吧,我在C中编写的库可以读取文件并提供对其数据的访问。数据是打字的,所以我使用了无效指针和一些访问函数:
typedef struct nbt_tag
{
nbt_type type; /* Type of the value */
char *name; /* tag name */
void *value; /* value to be casted to the corresponding type */
} nbt_tag;
int64_t *nbt_cast_long(nbt_tag *t)
{
if (t->type != TAG_LONG) return NULL;
return (int64_t *)t->value;
}
对于不同类型(内置插件:TAG_BYTE(char
),TAG_SHORT(int16_t
),TAG_INT(int32_t
),TAG_LONG(int64_t
),TAG_FLOAT({ {1}}),TAG_DOUBLE(float
),TAG_STRING(double
)和一些稍微复杂的数据类型,TAG_List(char *
),TAG_COMPOUND(struct nbt_list
), TAG_BYTE_ARRAY(struct nbt_compound
)。
我现在正试图以优雅的方式将其映射到C ++,但我无法完成它......
struct nbt_byte_array
这感觉太冗长了......还有更好的方法吗?
答案 0 :(得分:3)
这可以完成这项工作:
template <int> struct TypeTag {};
template <> struct TypeTag<TAG_BYTE> { typedef char type; };
// ...
template <> struct TypeTag<TAG_COMPOUND> { typedef vector<Tag> type; };
template <int tag>
typename TypeTag<tag>::type getValue(nbt_tab* t)
{
if (t->type != tag) ... // throw an exception
return *reinterpret_cast<typename TypeTag<tag>::type*>(t-value);
}
并像这样使用它:
char x = getValue<TAG_BYTE>(t);
vector<Tag> v = getValue<TAG_COMPOUND>(t);
您可能想要添加
等特色template <>
vector<Tag> getValue<TAG_COMPOUND>(nbt_tab* t)
{
if (t->type != TAG_COMPOUND) ... // throw something
vector<Tag> ans(/* size */); // [rely on named return value optimization]
// Fill the vector with your data
return ans; // [Pray for the copy constructor not to get called]
}
答案 1 :(得分:0)
你可以模板化这个功能。
template <typename T>
typename T get();
答案 2 :(得分:0)
不是一个直接的答案,但看看VARIANT(在Windows中),以及相应的CComVariant和_variant_t包装类:这基本上是相同的,你可能能够从如何在那里完成它的一些见解
我做过像模板转换这样的东西,其中复杂性在对象中,但它很容易使用,但是YMMV。
答案 3 :(得分:0)
有一些方法可以使用模板voodoo将其全部减少到get<X>()
函数(可能有一些特化)。但是,你可以通过编写那些getX
函数的简单性进行权衡,因为这些函数可能需要为模板机制和/或某些模板特化编写类似于小类型特征的基础结构。
如果支持的不同类型的数量永远(或很少)将会发生变化,那么最简单且最容易理解的可能只是那些不同的getX
函数。它可能很冗长,但这些函数应该非常快速地编写和调试。
另一方面,如果你对模板感到满意,你当然可以尝试这种方法。
答案 4 :(得分:0)
您可以使用boost :: variant。此类型可以存储它的任何模板参数,并且可以查询它包含的模板参数。只需将一堆它们放在一个向量中,然后返回对您喜欢的变体的引用。