根据C ++中的运行时字符串选择模板 [英] Choose template based on run-time string in C++
问题描述
我有一个可以容纳不同类型的属性向量:
I have an attribute vector that can hold different types:
class base_attribute_vector; // no template args
template<typename T>
class raw_attribute_vector : public base_attribute_vector;
raw_attribute_vector<int> foo;
raw_attribute_vector<std::string> foo;
基于类型的运行时输入,我想创建适当的数据结构。伪代码:
Based on run-time input for the type, I would like to create the appropriate data structure. Pseudocode:
std::string type("int");
raw_attribute_vector<type> foo;
显然,这失败了。一个简单但丑陋且无法维护的解决方法是在运行时进行切换/链接:
Obviously, this fails. An easy, but ugly and unmaintainable workaround is a run-time switch/chained if:
base_attribute_vector *foo;
if(type == "int") foo = new raw_attribute_vector<int>;
else if(type == "string") ...
我了解了运行函子的时间多态性,但发现对于在概念上很简单的任务而言,它相当复杂。
I read about run-time polymorphism with functors, but found it quite complex for a task that is conceptually easy.
什么是最好的和最干净的方法?我玩过 boost :: hana
,发现虽然我可以创建从字符串到类型的映射,但是查找只能在编译时完成:
What is the best and cleanest way to make this work? I played around with boost::hana
, finding that while I can create a mapping from string to type, the lookup can only be done at compile time:
auto types =
hana::make_map(
hana::make_pair(BOOST_HANA_STRING("int"), hana::type_c<int>),
hana::make_pair(BOOST_HANA_STRING("string"), hana::type_c<std::string>)
);
所有可能的类型在编译时都是已知的。任何建议,高度赞赏。在一个完美的解决方案中,我将在一个地方创建name-> type映射。然后,我会这样使用它
All possible types are known at compile-time. Any suggestions are highly appreciated. In a perfect solution, I would create the name->type mapping in a single place. Afterwards, I would use it like this
std::vector<base_attribute_vector*> foo;
foo.push_back(magic::make_templated<raw_attribute_vector, "int">);
foo.push_back(magic::make_templated<raw_attribute_vector, "std::string">);
foo[0]->insert(123);
foo[1]->insert("bla");
foo[0]->print();
foo[1]->print();
在编译时不需要此魔术。我的目标是拥有尽可能可读的代码。
It is not required for this magic to happen at compile time. My goal is to have as readable code as possible.
推荐答案
enum class Type
{
Int,
String,
// ...
Unknown
};
Type TypeFromString(const std::string& s)
{
if (s == "int") { return Type::Int; }
if (s == "string") { return Type::String; }
// ...
return Type::Unknown;
}
template <template <typename> class>
struct base_of;
template <template <typename> class C>
using base_of_t = typename base_of<C>::type;
然后是通用工厂
template <template <typename> class C>
std::unique_ptr<base_of_t<C>> make_templated(const std::string& typeStr)
{
Type type = TypeFromString(typeStr);
static const std::map<Type, std::function<std::unique_ptr<base_of_t<C>>()>> factory{
{Type::Int, [] { return std::make_unique<C<int>>(); } },
{Type::String, [] { return std::make_unique<C<std::string>>(); } },
// ...
{Type::Unknown, [] { return nullptr; } }
};
return factory.at(type)();
}
每个基础都需要专门化:
a specialization is needed for each base:
template <>
struct base_of<raw_attribute_vector> {
using type = base_attribute_vector;
};
然后
auto p = make_templated<raw_attribute_vector>(s);
这篇关于根据C ++中的运行时字符串选择模板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!