使用 mpl::vector 作为函数表
Use mpl::vector as function table
我正在编写一些读取XML字符串并使用XML文件中属性键匹配的值填充一些结构成员的C++。目前,第一次传递会产生键值对的 stl::unordered_map。下一步是解释值字符串,并将它们作为目标类型返回以存储在结构中。有些类型有点复杂,但我有可以转换它们的方法。
我想做的是使用 mpl::vector 使用 get_value_* 方法将键映射到结构成员以转换值。我认为它看起来有点像:
typedef boost::mpl mpl;
using namespace std;
template<string K, typename T, T& dest, boost::function<void(MapTypePtr, string, T& dest)> >
struct MapperRow {};
struct Mapper : mpl::vector<
MapperRow < "death_star_radius", Length, death_star.radius, get_value_units >,
MapperRow < "death_star_energy", Energy, death_star.energy, get_value_units >,
MapperRow < "operational", bool, death_star.operational, get_value_simple >,
MapperRow < "num_tie_fighters", int, death_star.tie_fighers, get_value_simple >
> {};
长度和能量类型是 boost::units::数量的类型定义。
这可以通过提升元编程来实现吗?如果我走在正确的轨道上,我该如何让它运行?我需要迭代 mpl::vector 吗?
这绝对是可能的(见下文),但我不确定这是否值得麻烦......您不能使用更简单的方法,也许是继承和多态性吗?
尽管如此,这里有一个使用Boost.MPL的工作解决方案:
// MapperRow holds the necessary parsing informations: type of the member,
// type of the object, pointer to the appropriate member, parsing function
template<typename Type, typename Clazz, Type Clazz::*Member,
void (*Parser)(const std::string &, Type &)>
struct MapperRow
{
typedef Type type;
typedef Clazz clazz;
typedef Type Clazz::*memberType;
static const memberType member;
typedef void (*parserType)(const std::string &, Type &);
static const parserType parser;
};
template <typename Type, typename Clazz, Type Clazz::*Member,
void (*Parser)(const std::string &, Type &)>
const typename MapperRow<Type, Clazz, Member, Parser>::memberType
MapperRow<Type, Clazz, Member, Parser>::member = Member;
template <typename Type, typename Clazz, Type Clazz::*Member,
void (*Parser)(const std::string &, Type &)>
const typename MapperRow<Type, Clazz, Member, Parser>::parserType
MapperRow<Type, Clazz, Member, Parser>::parser = Parser;
// fill iterates over a map key->MapperRow, trying to find the given key.
// if found, it calls the parsing function, otherwise it asserts false (should
// probably throw an exception instead)
template <typename Clazz, typename First, typename Last>
struct fill_impl
{
static void apply(Clazz &obj, const std::string &key,
const std::string &value)
{
typedef typename mpl::deref<First>::type entry;
static const char *curKey =
mpl::c_str< typename
mpl::first<entry>::type
>::value;
if (key == curKey)
{
typedef typename mpl::second<entry>::type Row;
Row::parser(value, obj.*Row::member);
}
else
{
fill_impl<
Clazz, typename
mpl::next<First>::type,
Last
>::apply(obj, key, value);
}
}
};
template <typename Clazz, typename Last>
struct fill_impl<Clazz, Last, Last>
{
static void apply(Clazz &obj, const std::string &key,
const std::string &value)
{
assert(false && "key not found");
}
};
template <typename Map, typename Clazz>
void fill(Clazz &obj, const std::string &key, const std::string &value)
{
fill_impl<
Clazz, typename
mpl::begin<Map>::type, typename
mpl::end<Map>::type
>::apply(obj, key, value);
}
样品使用:
template <typename T>
void get_value_units(const std::string &str, T &value)
{
value = T::from_value(boost::lexical_cast<typename T::value_type>(str));
}
template <typename T>
void get_value_simple(const std::string &str, T &value)
{
value = boost::lexical_cast<T>(str);
}
typedef boost::units::quantity<boost::units::si::energy> Energy;
typedef boost::units::quantity<boost::units::si::length> Length;
struct DeathStar
{
Length radius;
Energy energy;
bool operational;
int tie_fighters;
};
// Could be clearer with MPLLIBS_STRING*
typedef mpl::map<
mpl::pair<
mpl::string<'deat','h_st','ar_r','adiu','s'>,
MapperRow< Length , DeathStar, &DeathStar::radius,
&get_value_units<Length> > >,
mpl::pair<
mpl::string<'deat','h_st','ar_e','nerg','y'>,
MapperRow< Energy, DeathStar, &DeathStar::energy,
&get_value_units<Energy> > >,
mpl::pair<
mpl::string<'oper','atio','nal'>,
MapperRow< bool, DeathStar, &DeathStar::operational,
&get_value_simple<bool> > >,
mpl::pair<
mpl::string<'num_','tie_','figh','ters'>,
MapperRow< int, DeathStar, &DeathStar::tie_fighters,
&get_value_simple<int> > >
> death_star_map;
int main()
{
DeathStar ds;
fill<death_star_map>(ds, "death_star_radius", "12");
fill<death_star_map>(ds, "death_star_energy", "34");
fill<death_star_map>(ds, "operational", "1");
fill<death_star_map>(ds, "num_tie_fighters", "56");
std::cout << "Radius: " << ds.radius << 'n';
std::cout << "Energy: " << ds.energy << 'n';
std::cout << "Operational: " << std::boolalpha << ds.operational << 'n';
std::cout << "Tie fighters: " << ds.tie_fighters << 'n';
}
* MPLLIBS_STRING
相关文章:
- 编译器如何区分std::vector的构造函数
- 为什么std::vector和std::valarray初始化构造函数不同
- 字符串化递归的"std::vector<std::vector<...>>"而不使用部分模板函数专用化
- std::vector::p ush_back() 不会在 MSVC 上编译具有已删除移动构造函数的对象
- std::vector 没有重载函数的实例与参数列表匹配
- 如何为 std::vector 分配内存,然后稍后为某些元素调用构造函数?
- 创建一个没有复制构造函数的类的 std::vector 的 std::vector
- 为 std::vector 编写自定义插入函数
- 从返回 std::optional of std::vector 的函数中获取结果到调用方
- 将 vector<vector<int>> 传递到函数中会产生内存错误
- 是否可以将具有不同签名的 lambda 存储在 std::vector 中并在函数中执行它们(使用各自的参数)?
- 将 cv::Mat 转换为 std::vector 的通用函数
- 从 std::vector 迭代器中执行函数指针
- C++ std::vector 中的虚拟析构函数继承
- 错误:调用"es_queue::set_rpc_vector(std::vector >&, std::__cxx11::string)"没有匹配函数
- 当我从 std::vector 中的新放置调用析构函数时会发生什么?
- 对于优化级别为 0 的 std::vector,析构函数被调用两次
- push_back std::vector,则重复调用复制构造函数
- 如何在构造函数初始值设定项列表中使用 n 个元素初始化 std::vector<std::time_t>
- 双重调用传递给 std::vector::emplace_back 的类的复制构造函数