gpt4 book ai didi

c++ - 在编译时使用模板填充运行时数据

转载 作者:搜寻专家 更新时间:2023-10-31 01:33:55 25 4
gpt4 key购买 nike

我有一个特定的情况,我想在编译时准备一些运行时结构而不需要复制代码。

我有两个结构,用于在编译时为我编写的编译器注册某些类型:

using TypeID = u8;

template<typename T, typename TYPE_ID, TYPE_ID I>
struct TypeHelper
{
static constexpr TYPE_ID value = std::integral_constant<TYPE_ID, I>::value;
};

template<typename T> struct Type : TypeHelper<T, u8, __COUNTER__> { static_assert(!std::is_same<T,T>::value, "Must specialize for type!"); };

这些在配置 header 中使用,带有专门用于 Type<T> 的宏对于我需要的多种类型:

using type_size = unsigned char;

#define GET_NTH_MACRO(_1,_2,_3, NAME,...) NAME
#define REGISTER_TYPE(...) GET_NTH_MACRO(__VA_ARGS__, REGISTER_TYPE3, REGISTER_TYPE2, REGISTER_TYPE1)(__VA_ARGS__)

#define REGISTER_TYPE1(_TYPE_) REGISTER_TYPE2(_TYPE_, _TYPE_)

#define REGISTER_TYPE2(_TYPE_,_NAME_) \
constexpr TypeID TYPE_##_NAME_ = __COUNTER__; \
template<> struct Type<_TYPE_> : TypeHelper<_TYPE_, type_size, TYPE_##_NAME_> { \
static constexpr const char* name = #_NAME_; \
};

REGISTER_TYPE(void)
REGISTER_TYPE(s64)
REGISTER_TYPE(s32)

让这些扩展到

constexpr TypeID TYPE_void = 2; 
template<> struct Type<void> : TypeHelper<void, type_size, TYPE_void> { static constexpr const char* name = "void"; };

constexpr TypeID TYPE_s64 = 3;
template<> struct Type<s64> : TypeHelper<s64, type_size, TYPE_s64> { static constexpr const char* name = "s64"; };

constexpr TypeID TYPE_s32 = 4;
template<> struct Type<s32> : TypeHelper<s32, type_size, TYPE_s32> { static constexpr const char* name = "s32"; };

这工作正常,但编译器还需要有关这些类型的一些运行时信息,因此除此之外,我必须定义一些辅助函数,如

static TypeID typeForIdent(const std::string& name);
static const char* nameForType(TypeID type);
static void mapTypeName(TypeID type, const std::string& name);

inline bool isSigned(TypeID type)
{
return type == Type<s8>::value || type == Type<s16>::value ||
type == Type<s32>::value || type == Type<s64>::value;
}

和类似的功能。

这些函数必须在没有模板参数的情况下工作,因此 TypeID必须是一个正常的论点。但是我需要在单独的代码部分中初始化此类数据,例如:

mapTypeName(Type<s32>::value, "s32");

它使用静态 std::unordered_map<TypeID, std::string> .当然,这也意味着当大多数信息在编译时通过类型定义已经可用时,我必须维护两倍的代码。

我想知道是否有一些我遗漏的晦涩技巧可以合并这些技巧以便 REGISTER_TYPE宏还注册了运行时信息。我还没有带来任何东西,但也许有一个聪明的方法来管理它。

最佳答案

如果您不是特别关心将运行时数据注册到 map 中的性能,您可以简单地使用一个 inline 函数返回一个对 static 的引用> 映射实例,并在你的 REGISTER_TYPE 宏中生成 “dummy” registrar 实例,在它们的构造函数中填充映射。


inline auto& registration_map()
{
static std::unordered_map<int, std::string> m;
return m;
}

struct registrar
{
registrar(int id, std::string s)
{
registration_map()[id] = std::move(s);
}
};

template <typename T>
struct TypeHelper { };

#define CAT3_IMPL(a, b, c) a ## b ## c
#define CAT3(a, b, c) CAT3_IMPL(a, b, c)

#define REGISTER_TYPE(id, type) \
template<> struct TypeHelper<type> { }; \
[[maybe_unused]] registrar CAT3(unused_registrar_, __LINE__, type) {id, #type};

REGISTER_TYPE(0, int)
REGISTER_TYPE(1, float)
REGISTER_TYPE(2, double)

int main()
{
assert(registration_map()[0] == "int");
assert(registration_map()[1] == "float");
assert(registration_map()[2] == "double");
}

Full example on wandbox .


注意事项:

  • 如果多个翻译单元中包含相同的 REGISTER_TYPE,您可能会重复注册。

  • CAT3(unused_registrar_, __LINE__, type) 用于生成不会与其他 REGISTER_TYPE 扩展冲突的唯一名称。

    <

关于c++ - 在编译时使用模板填充运行时数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40490166/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com