jbeder / yaml-cpp

A YAML parser and emitter in C++
MIT License
4.92k stars 1.78k forks source link

add a second default template parameter for YAML::convert so users ca… #1145

Closed ghost closed 1 year ago

ghost commented 1 year ago

a little change. I added a second default template parameter for YAML::convert so users can use SFINAE to partial specialized it. I have tested this:

template <typename T>
struct convert<T, std::enable_if_t<std::is_enum_v<T>>>
{
    static Node encode(const T &rhs)
    {
        Node node;
        node = std::string(enum_enhanced::enum_to_string(rhs));
        return node;                                                     
    }                                                                    

    static bool decode(const Node &node, T &rhs)
    {
        rhs = enum_enhanced::enum_from_string<T>(node.as<std::string>());
        return true;
    }
};

enum_enhanced::enum_to_string can convert all enum to std::string. enum_enhanced::enum_from_string<T> convert std::string to enum. It come from here:

#pragma once

#include <string>
#include <type_traits>

namespace enum_enhanced
{
namespace enum_enhanced_impl
{
template <class T, T N>
char const *pretty_string()
{
#ifdef _MSC_VER
    return __FUNCSIG__;
#else
    return __PRETTY_FUNCTION__;
#endif
}

template <class T>
struct PrettyStringCaller
{
  public:
    int          n;
    std::string &s;

  public:
    template <int I>
    void Call() const
    {
        if (n == I)
            s = pretty_string<T, static_cast<T>(I)>();
    }
};

template <int Start, int End, class F>
typename std::enable_if<Start == End>::type static_for(F const &caller)
{
}

template <int Start, int End, class F>
typename std::enable_if<Start != End>::type static_for(F const &caller)
{
    caller.template Call<Start>();
    static_for<Start + 1, End>(caller);
}
}  // namespace enum_enhanced_impl

template <class T, int Start = 0, int End = 64>
std::string enum_to_string(T n)
{
    static_assert(Start < End);

    using namespace enum_enhanced_impl;

    std::string string;
    static_for<Start, End>(PrettyStringCaller<T>{.n = static_cast<int>(n), .s = string});

#ifdef _MSC_VER
    size_t end   = string.find_last_of('>');
    size_t start = string.find_last_of(',', end) + 1;
#else
    size_t start = string.find("N = ") + 4;
    size_t end   = string.find(']', start);
#endif
    string = string.substr(start, end - start);
    if ((start = string.find_last_of(":")) != string.npos)
    {
        string = string.substr(start + 1, string.size() - start);
    }

    return string;
}

template <class T, int Start = 0, int End = 64>
T enum_from_string(std::string const &str)
{
    static_assert(Start < End);

    using namespace enum_enhanced_impl;

    for (int i = Start; i < End; i++)
    {
        if (!str.compare(enum_to_string<T, Start, End>(static_cast<T>(i))))
        {
            return static_cast<T>(i);
        }
    }

    throw;
}

}  // namespace enum_enhanced