如何为特定类型的访问函数编写通用模板包装器?
How to write a generic templated wrapper for type specific acess functions?
我正在尝试为 C++ pugi xml 库编写一个通用包装器,它可以保存和存储值 to/from xml.
他们已经将 xml 节点属性(存储为字符串)访问函数实现为 attribute.as_int()
、attribute.as_bool()
等函数
我想实现在 nlohmann::json 库中看到的相同功能,您可以在其中调用 .get<T>()
一些 json 对象并获取一些类型。
我能想到的唯一方法(甚至可能行不通)是使用模板专业化:
template <>
int foo<int>(xml_attribute param)
{
return param.as_int();
}
template <>
bool foo<bool>(xml_attribute param)
{
return param.as_bool();
}
等等。
这似乎导致编写的代码几乎与编写非通用包装器一样多...
嗯,你的方法其实还不错。我可能会坚持下去。
然而还有另一种方法。
#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
}
我们可以使用一个额外的参数来根据类型创建不同的重载,然后使用重载解析来找到正确的函数。 TypeTag
是一个空 class 我们可以用来区分不同的重载:
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
检查更快,因为编译器可以通过重载解析查找正确的版本,而不必执行一系列检查检查。
我正在尝试为 C++ pugi xml 库编写一个通用包装器,它可以保存和存储值 to/from xml.
他们已经将 xml 节点属性(存储为字符串)访问函数实现为 attribute.as_int()
、attribute.as_bool()
等函数
我想实现在 nlohmann::json 库中看到的相同功能,您可以在其中调用 .get<T>()
一些 json 对象并获取一些类型。
我能想到的唯一方法(甚至可能行不通)是使用模板专业化:
template <>
int foo<int>(xml_attribute param)
{
return param.as_int();
}
template <>
bool foo<bool>(xml_attribute param)
{
return param.as_bool();
}
等等。
这似乎导致编写的代码几乎与编写非通用包装器一样多...
嗯,你的方法其实还不错。我可能会坚持下去。
然而还有另一种方法。
#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
}
我们可以使用一个额外的参数来根据类型创建不同的重载,然后使用重载解析来找到正确的函数。 TypeTag
是一个空 class 我们可以用来区分不同的重载:
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
检查更快,因为编译器可以通过重载解析查找正确的版本,而不必执行一系列检查检查。