在前面分析过,反射有静态和动态两类形式,前者在编译期实现,后者在运行期实现。而针对c++这类天然不支持(或者说极弱支持)反射的语言,在实现上又可以分为侵入式和非侵入式实现。这个就更好理解了,侵入式需要在原代码上增加一些辅助代码,而非侵入式则不需要增加辅助代码。这个只要过一下脑子当然是后者好,但实际应用上到底哪种好,得看实际情况,不能一概而论。
在前面的文章《C++中两个宏PRETTY_FUNCTION__和__FUNCSIG的应用》介绍过这两个宏(其实是一种宏),它可以对c++程序在编译期和运行期的问题所在有一个记录并反馈给开发者(也提到过使用这个宏可以实现一种编译期反射的方法)。但是不知道有没有读者注意到那篇文章的例程中运行结果的一些细节,它可以得到一些参数的类型。噢,这不就是反射想达到的一种目的么?那可不可以利用这个宏来实现一种反射的方式呢?答案是肯定的。先看一个简单的例子入手:
#include <iostream>
#ifdef _WIN64
#define __FUNC__ __FUNCSIG__
#else
#define __FUNC__ __PRETTY_FUNCTION__
#endif
template<typename T>
constexpr void Func()
{
std::cout << __FUNC__ << std::endl;
}
void getType() {
Func<int>();
}
int main()
{
getType();
}
它的运行结果是:
//gcc
constexpr void Func() [with T = int]
这是不是很明显可以看到T的类型是int,那么最暴力最原始的方法就是直接对这个字符串进行解析,然后得到T和int,这样不就可以得类型了么。看一下下面的例子:
#include <iostream>
#include <string>
#ifdef _WIN64
#define __FUNC__ __FUNCSIG__
#else
#define __FUNC__ __PRETTY_FUNCTION__
#endif
std::string_view parseResult(std::string result) {
//str = constexpr void Func() [with T = int]
auto begin = result.find("T = ") + 4;
auto end = result.find_last_of("]");
return std::string_view{ result.data() + begin, end - begin };
}
template<typename T>
constexpr auto TypeInfo() {
auto result = __FUNC__;
return parseResult(result);
}
class Example{
int d = 0;
void GetData(){std::cout<<"test"<<std::endl;}
};
int main()
{
auto type = TypeInfo<Example>();
std::cout<<type<<std::endl;
type = TypeInfo<int>();
std::cout<<type<<std::endl;
type = TypeInfo<double>();
std::cout<<type<<std::endl;
}
运行结果:
Example
int
double
当然针对不同的编译器和平台可能还会需要进行细节上的修改,但整体上的原则基本是相同的。
下面再看一个针对枚举体的例程。枚举体是一种比较特殊的情况,它可以和整数隐式转换。C++11又推出了枚举类,看看下面的例子:
#include <iostream>
#include <string>
#ifdef _WIN64
#define __FUNC__ __FUNCSIG__
#else
#define __FUNC__ __PRETTY_FUNCTION__
#endif
enum class DataType{USB,PCI,HD};
enum DType{USB,PCI,HD};
template<auto T>
constexpr auto TypeInfo()
{
std::string type = __FUNC__;
auto begin = type.find("T = ") + 4;
auto end = type.find_last_of(']');
return std::string_view{ type.data() + begin, end - begin };
}
int main()
{
std::cout<<Func1<DataType::HD>()<<std::endl;
std::cout<<Func1<DType::HD>()<<std::endl;
}
运行结果:
DataType::HD
HD
今天把使用宏PRETTY_FUNCTION来实现静态非侵入式的反射进行了一个初步的分析说明,然后下一步将继续分析枚举的反射,从此处打开一个缺口,让大家更好的明白反射的实现方式的一个切入点。
反射写起来非常头痛,一个是不知道如何说起更有系统性;另外一个就是哪种反射更有利于实际的应用。所以反射这个系列可能会是一个很长期的总结过程,大家不要着急,一定会把坑慢慢填好。
网站声明:如果转载,请联系本站管理员。否则一切后果自行承担。
加入交流群
请使用微信扫一扫!