如何为类型特定的访问函数编写通用模板化包装器?

时间:2019-04-10 21:42:07

标签: c++ pugixml

我正在尝试为C ++ pugi xml库编写一个通用包装,该包装可以将值保存到xml或从xml存储值。

他们已将其xml节点属性(存储为字符串)访问功能实现为attribute.as_int()attribute.as_bool()等功能。

我想实现nlohmann :: json库中所见的相同功能,您可以在其中调用某些json对象上的.get<T>()并获得某种类型。

我能想到的唯一方法(甚至可能不起作用)是使用模板特化:

template <>
int foo<int>(xml_attribute param)
{
    return param.as_int();
}

template <>
bool foo<bool>(xml_attribute param)
{
    return param.as_bool();
}

依此类推。

似乎所产生的代码几乎与编写非通用包装器一样多...

2 个答案:

答案 0 :(得分:2)

嗯,您的方法实际上还不错。我可能会坚持下去。

但是,还有另一种方式。

#include <type_traits>

template <typename T>
auto foo(xml_attribute param)
{
    if constexpr (std::is_same<T, int>::value) {
          return param.as_int();
    }
    else if constexpr (/*..*/){//...} //and so on
}

答案 1 :(得分:1)

我们可以使用一个额外的参数根据类型创建不同的重载,然后使用重载分辨率找到正确的函数。 TypeTag是一个空类,我们可以用来区分不同的重载:

template<class T>
struct TypeTag{ /* empty */ };

有了这些,就可以基于标记编写read_as函数:

int read_as(xml_attribute param, TypeTag<int>) {
    return param.as_int(); 
}
bool read_as(xml_attribute param, TypeTag<bool>) {
    return param.as_bool(); 
}
float read_as(xml_attribute param, TypeTag<float>) {
    return param.as_float(); 
}
double read_as(xml_attribute param, TypeTag<double>) {
    return param.as_double();
}
const pugi::char_t* read_as(xml_attribute param, TypeTag<const pugi::char_t*) {
    return param.as_string(); 
}

制作通用模板非常简单:

template<class T>
T read_as(xml_attribute param) {
    return read_as(param, TypeTag<T>()); 
}

此解决方案在C ++ 11中有效,并且其编译速度比一系列if constexpr检查更快,因为编译器可以通过重载解析来查找正确的版本,而不必进行一系列检查。