C ++ шаблон специализация в подшаблонах - PullRequest
4 голосов
/ 11 октября 2019

В json.h У меня есть:

template <class T>
Json::Value write_json(const T& object);

В json.cpp :

template <>
Json::Value write_json(const bool& object) {
    Json::Value output;
    output = object;
    return output;
};

template <>
Json::Value write_json(const int& object) {
    Json::Value output;
    output = object;
    return output;
};

template <>
Json::Value write_json(const std::vector<bool>& v) {
    Json::Value output;
    for (auto it = v.begin(); it != v.end(); ++it) { output.append(*it); };
    return output;
};

template <>
Json::Value write_json(const std::vector<int>& v) {
    Json::Value output;
    for (auto it = v.begin(); it != v.end(); ++it) { output.append(*it); };
    return output;
};

Есть ли способ в C ++ , чтобы специализировать базовые типы на одном «подшаблоне» и контейнеры на другом?

1 Ответ

6 голосов
/ 11 октября 2019

C ++ 17 Solution

Давайте начнем с черты, чтобы проверить, получаете ли вы контейнер или нет:

template<class ...>
using void_t = void;    

template<class T, class = void>
struct is_container : std::false_type{};

template<class T>
struct is_container<T, void_t<decltype(std::begin(std::declval<T>())), decltype(std::end(std::declval<T>()))>> : std::true_type{};

template<class T>
constexpr auto is_container_v = is_containter<T>::value;

С этим вы можете просто сделать:

template <class T>
Json::Value write_json_primitive(const T& object) {
    static_assert(!is_container_v<T>);
    Json::Value output;
    output = object;
    return output;
};

template <class T>
Json::Value write_json_container(const T& v) {
    static_assert(is_container_v<T>);
    Json::Value output;
    for (const auto& val : v) { output.append(val); };
    return output;
};

template <class T>
Json::Value write_json(const T& object) {
    if constexpr (is_container_v<T>)
        return write_json_container(object);
    else
        return write_json_primitive(object);
}

Sidenote: этот код требует поддержки C ++ 17. Если вам явно нужен C ++ 11, это можно сделать, но немного по-другому

C ++ 11 Solution

Здесь нужно немного больше метапрограммирования, и static_asserts не может использоваться так легко, но все же ясделал это:

template<typename... Ts> struct make_void { typedef void type;};
template<typename... Ts> using void_t = typename make_void<Ts...>::type;


template<class T, class = void>
struct is_container : std::false_type{};

template<class T>
struct is_container<T, void_t<decltype(std::begin(std::declval<T>())), decltype(std::end(std::declval<T>()))>> : std::true_type{};

template <class T>
Json::Value write_json_primitive(const T& object) {
    Json::Value output;
    output = object;
    return output;
};

template <class T>
Json::Value write_json_container(const T& v) {
    Json::Value output;
    for (const auto& val : v) { output.append(val); };
    return output;
};


template<class T>
using json_function = std::conditional<
        is_container<T>::value,
            std::integral_constant<decltype(&write_json_container<T>), &write_json_container<T>>,
            std::integral_constant<decltype(&write_json_primitive<T>), &write_json_primitive<T>>>;

template <class T>
Json::Value write_json(const T& object) {
    return json_function<T>::type::value(object);
}

Надеюсь, это будет работать как шарм;)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...