C-中的编译期反射

C++的编译期反射

我们可以利用__PRETTY_FUNCTION__这个宏获取当前函数的签名。
比如以下代码:

#include<fmt/core.h>
#include<string>

template<typename T>
std::string get_type_name(T n)
{
    return __PRETTY_FUNCTION__ ;
}

int main(int argc, char*  argv[])
{
      fmt::print(get_type_name<int>(3)+"\n");
}

输出:

std::string get_type_name(T) [with T = int; std::string = std::__cxx11::basic_string<char>]

如果是在Windows平台上,需要加上

#if !defined(__PRETTY_FUNCTION__) && !defined(__GNUC__)
#define __PRETTY_FUNCTION__ __FUNCSIG__
#endif

输出会是:

class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl get_type_name<int>(void)

为了方便叙述,后面还是主要以Linux平台为例。我们接下来就可以利用字符串切片得到编译器推导的类型,比如

template<typename T>
std::string get_type_name() {
    std::string function_sign{__PRETTY_FUNCTION__ };
    std::string_view find_str = "T = ";
    std::size_t size_str = find_str.size();
    std::size_t pos = function_sign.find(find_str);
    pos+=size_str;
    std::size_t pos2 = function_sign.find_first_of(";", pos);
    return function_sign.substr(pos, pos2-pos);
}

假如我们输出get_type_name<uint32_t>会得到unsigned int

同样我们可以输出数值模板推导的值:

template<typename T, T n>
std::string get_int_name(){
    std::string function_sign{__PRETTY_FUNCTION__ };
    std::string_view find_str = "n = ";
    std::size_t size_str = find_str.size();
    std::size_t pos = function_sign.find(find_str);
    pos+=size_str;
    std::size_t pos2 = function_sign.find_first_of(";", pos);
    return function_sign.substr(pos, pos2-pos);
}
fmt::print(get_int_name<char , 2>()+'\n');

我们会输出得到\002

假如我们想推导一个运行期的enum变量的值呢?

template<int begin_, int end_, typename F>
void static_for(F const& func){
    if constexpr (begin_ == end_) return;
    else{
        func(std::integral_constant<int, begin_>());
        static_for<begin_+1, end_>(func);
    }
}

template<typename T>
std::string get_int_name_dynamic(T n){
    std::string ret;
    static_for<0,6>([&](auto ic){
        constexpr auto i = ic.value;
        if(n == static_cast<T>(i)) ret = get_int_name<T, static_cast<T>(i)>();
    });
    return ret;
}

自然,我们可以直接反过来通过枚举名字符串返回一个枚举变量:

template<typename T, int begin_=0, int end_=256>
T enum_from_name(std::string const& enum_name){
   for(int i=begin_;i!=end_;i++)
   {
       if(enum_name == get_int_name_dynamic(static_cast<T>(i)))
           return static_cast<T>(i);
   }
   throw;
}

本文作者:WYFC4

本文链接:https://www.cnblogs.com/wyfc4/p/17519815.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   WYFC4  阅读(73)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.