当前位置: 首页 > article >正文

跟我学c++高级篇——动态反射之一遍历

一、动态反射

前面讲一篇静态反射,今天在这个基础上对动态反射进行一下入门。动态反射前面提到过,一般是指在运行时动态获取类型或者生成实例。那么如何才能动态获得类型呢?方法有很多种,下面从最简单的开始。

二、入门程序

动态反射的一个简单例子如下:

#include <tuple>
#include <string>
#include <unordered_map>
#include <iostream>

enum class RgbColor {RGB_RED,RGB_BLACK,RGB_WHITE,NOTHING};

std::tuple<std::string, std::string, std::string> tDesc = {"red","black","white"};
std::unordered_map<std::string, RgbColor> mapColor = { {"red",RgbColor::RGB_RED},{"black",RgbColor::RGB_BLACK},{"white",RgbColor::RGB_WHITE}};

RgbColor strToType(const std::string& color)
{
	auto num = mapColor.count(color);
	if (num > 0) {
		return mapColor[color];
	}
	else {
		return RgbColor::NOTHING;
	}
}

void GetColorTest(const std::string&str)
{
	auto color = strToType(str);
	std::cout << "str is:" << str << "," << "Color is:" << static_cast<int>(color) << std::endl;
}

但是这么做除了麻烦外还容易出错。另外为了一个简单的反射,写了如此多的不可重用的代码确实也让人觉得有点低效。

三、使用__PRETTY_FUNCTION__

其实动态反射的核心在动态类型的获取,那么可以在前面使用__PRETTY_FUNCTION__的基础上对其进行处理,从而使其可以在运行获取对象的类型:

#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>
auto TypeInfo()
{
    std::string type = __FUNC__;
    auto s = type.find("T = ") + 4;
    auto e = type.find_last_of(']');
    return std::string_view{ type.data() + s, e - s };
}

template<typename T>
std::string_view Typeof(T t)
{
   int t1 = static_cast<int>(t);
    if (t1 == 0)
    {
        return TypeInfo<DataType::USB>();
    }

    if (t1 == 1)
    {
        return TypeInfo<DataType::PCI>();
    }
    if (t1 == 2)
    {
        return TypeInfo<DataType::HD>();
    }
    return std::string_view("");
}

void getTypeTest()
{
    std::cout << Typeof(DataType::HD) << std::endl;
    std::cout << Typeof<DType>(DType::PCI) << std::endl;
}

int main()
{
    getTypeTest();
    return 0;
}

上面这些代码其实和最初的代码不同点在于他可以动态的适应名称的变化和相关内容的增加而不需要增加代码的编写和维护。可是上面的代码还是有些麻烦,比如枚举的值不断的增加,那么if语句就这么一直增加下去么?可行是可行的,但有点不爽,可以写成下面的形式:

#include <iostream>
#include <string>
#include <type_traits>

#ifdef _WIN64
#define __FUNC__ __FUNCSIG__
#else
#define __FUNC__  __PRETTY_FUNCTION__
#endif

enum class DataType{USB,PCI,HD,NOT};
enum  DType{USB,PCI,HD,NOT};
template<auto T>
 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 };
}

template <int s, int e>
struct static_for
{
    template<typename F>
    void operator()(const F& func) const
    {
        if (s < e)
        {
            //注意:一定要转成常量
            func(std::integral_constant<int,s>());
            static_for<s + 1, e>()(func);
        }
    }
};

template <int n>
struct static_for<n, n>
{
    template<typename F>
    void operator()( const F & func) const
    {
       // std::cout << "noting" << std::endl;
    }
};
constexpr int s = static_cast<int>(DataType::USB);
constexpr int e = static_cast<int>(DataType::NOT);

template<typename T>
std::string_view Typeof(T t)
{
   int t1 = static_cast<int>(t);
   std::string_view sv;
       static_for<s, e>()([&](auto num) {
        if (t1 == num) {
             //重点要理解const和num.value
             const DataType d = DataType{num.value};
            sv = TypeInfo<d>();
            }
            });

    return sv;
}

void getTypeTest()
{
    std::cout << Typeof(DataType::HD) << std::endl;
    //std::cout << Typeof<DType>(DType::PCI) << std::endl;
}

int main()
{
        getTypeTest();
        return 0;
}

使用了一个static_for,它的实现方式有很多种,这里用的是类似变参模板的递归方式,也可以使用条件判断的方式,也可以直接写到一个模板函数中,都可以实现类似的方式。重点是需要它展开模板,实现类似循环即可。

四、总结

这篇内容就有点接近正常理解的反射的意思了,本来这篇想把一个动态表生成的方式也分析了,但是又觉得太长了,还是分到下一篇再一起分享。慢慢来,不要急。


http://www.kler.cn/a/155148.html

相关文章:

  • 一键生成本地SSL证书:打造HTTPS安全环境
  • 1.两数之和-力扣(LeetCode)
  • 自由学习记录(21)
  • 基于Python的网上银行综合管理系统
  • 数字后端教程之Innovus report_property和get_property使用方法及应用案例
  • HTTP协议基础
  • 代码浅析DLIO(四)---位姿更新
  • LeetCode(49)用最少数量的箭引爆气球【区间】【中等】
  • 基本计算器[困难]
  • 【日常踩坑】Debug 从入门到入土
  • 完美解决:wget命令下载时遇到“错误 308:Permanent Redirect。”
  • 大数据Hadoop-HDFS_架构、读写流程
  • 【小沐学Python】Python实现Web服务器(Flask+celery,生产者-消费者)
  • LeetCode每日一题 | LeetCode-1094.拼车
  • 栈实现队列,力扣
  • ESP32-Web-Server 实战编程-通过网页控制设备的 GPIO
  • MVCC-
  • 【.NET全栈】.net的微软API接口与.NET框架源码
  • LLM推理部署(三):一个强大的LLM生态系统GPT4All
  • AI - FlowField(流场寻路)
  • 2023年第十二届数学建模国际赛小美赛B题工业表面缺陷检测求解分析
  • 外包干了2年,技术退步明显。。。
  • solidity案例详解(五)能源电力竞拍合约
  • FDM3D打印系列——天秤座黄金圣斗士模型制作全过程视频
  • 微服务的流量管理-服务网格
  • 使用Draw.io制作泳道图