C++枚举类型转字符串,非侵入式静态反射

本文介绍了如何在C++中实现枚举类型转字符串的功能,采用非侵入式静态反射的方法,适用于C++11及以上标准。详细讲述了参考资源、源码实现以及需要注意的事项,特别指出该方法在GCC下测试通过,理论上也兼容MSVC,但可能会增加编译时间。

C++枚举类型转字符串

1. 参考

【鲜为人知的C++黑科技【PRETTY_FUNCTION】非侵入式的编译期反射-哔哩哔哩】

2. 源码

enum_enhanced.hpp

/**
 * @file enum_enhanced.hpp
 * @author chenpi001 (cp12138@duck.com)
 * @brief convertion between enum and std::string, need c++11 or above
 * @version 0.1
 * @date 2022-08-03
 *
 * @copyright Copyright (c) 2022
 *
 */
#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_imple

    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

main.cpp

#include <iostream>
#include "enum_enhanced.hpp"

enum Student
{
    Bob,
    Lisa = 10,
    Ada
};

int main(int argc, char **argv)
{
    Student a = Student::Bob;
    std::cout << enum_enhanced::enum_to_string(a) << std::endl;
    std::cout << enum_enhanced::enum_to_string(Student::Ada) << std::endl;
    return 0;
}

输出

Bob
Ada

3. 注意

  1. 强烈推荐参考讲解自己实现,加强对元编程的理解
  2. 需要C++标准为C++11或以上,参考的原作者提供了C++98的实现方法
  3. 默认枚举类型的范围为[0,64],如果超过范围可主动设置模板中的Start和End值
  4. 会导致编译时间增加
  5. 只在gcc下使用过,理论上适配了msvc
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值