Как написать шаблонную оболочку для шаблонных функций доступа? - PullRequest
1 голос
/ 11 апреля 2019

Я пытаюсь написать универсальную оболочку для библиотеки C ++ pugi xml, которая может сохранять и сохранять значения в / из 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();
}

и т. Д.

Что приводит к тому, что кода получается почти столько же, сколько и к написанию не универсальной оболочки ...

Ответы [ 2 ]

2 голосов
/ 11 апреля 2019

Ну, ваш подход на самом деле не так уж и плох. Я, вероятно, буду придерживаться этого.

Однако есть и другой способ.

#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 голос
/ 11 апреля 2019

Мы можем использовать дополнительный параметр для создания различных перегрузок в зависимости от типа, а затем использовать разрешение перегрузки, чтобы найти нужную функцию.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 проверок, потому что компилятор может найти правильную версиючерез разрешение перегрузки, вместо того, чтобы выполнять серию проверок.

...