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;
}
标签:std,__,name,反射,get,编译,size,string
From: https://www.cnblogs.com/wyfc4/p/17519815.html