如何实现类型名跟类型的对应, 我们很容易想到map, 没错, 就是使用map实现的. std::map
由于声明这个容器是并不能包含模板参数, 这里借鉴了boost 库中any的代码, 原理如下:
1 class Container {
2
3 private:
4
5 class bridge {
6
7 public:
8 bridge(){}
9 virtual ~bridge(){}
10 virtual void invoke(unsigned long long addr, const std::vector<const char*>& args) = 0;
11 virtual void* instanceOfClass() = 0;
12 };
13
14 template<typename ValueType>
15 class holder: public bridge {
16
17 public:
18 virtual void invoke(unsigned long long addr, const std::vector<const char*>& args) override{};
19 virtual void* instanceOfClass() override{};
20 };
21
22 template<typename ValueType>
23 class holder<ValueType*>: public bridge {
24
25 public:
26 holder(ValueType* item){}
27 virtual ~holder() {}
28
29 virtual void invoke(unsigned long long addr, const std::vector<const char*>& args) override{
30
31 }
32
33 virtual void* instanceOfClass() override{
34
35 36 37 }
38 };
39
40 bridge* content_;
41 public:
42 Container(){}
43 ~Container(){
44 Alloc::dellocate(content_);
45 }
46
47 template<typename ValueType>
48 Container(ValueType* item) {
49
50 holder<ValueType*>* h = static_cast<holder<ValueType*>*>(Alloc::allocate(sizeof(holder<ValueType*>)));
51 new(h) holder<ValueType*>(item);
52 content_ = h;
53 }
54
55 // three arguments most, and type are char*
56 void invoke(unsigned long long addr, const std::vector<const char*>& args) {
57
58 content_->invoke(addr, args);
59 }
60
61 void* instanceOfClass() {
62
63 return content_->instanceOfClass();
64 }
65
66 };
Container只是一层包装, 隐藏了模板参数, 真正存储类型的是继承bridge的holder子类, bridge提供接口, 由于纯虚函数不能是模板函数, 所以返回实例是必须强制转型为void* 指针, 由客户端再强制转型回来.如何存储一个类类型的信息呢, 最简单, 保存该类型的一个指针变量就行. 其他的交由编译器的模板处理. 然后将类注册, 即插入map中. 可以通过宏来实现.
好了, 到了最后一步, 函数类型问题. 我们的目标是在配置文件中声明类似的语句:
只要这样声明就能生产 void declation(const Init*, One, Two)这样的函数声明.
由于文本中只能保存基本的类型, 你不可能用在文本中指定某个参数是指针吧. 还有是函数个数的问题, 我本以为模板的可变参数能起点作用, 结果发现并不是我想要的. 好吧, 所以只能再做一个限制条件, 3个参数最多, 如果你写的函数参数多余三个, 我想你肯定有办法减少参数个数的, 还有参数类型都是字符串, 从字符串到其他基本类型的转换必须由函数自己解决. 这样, 解决思路很清晰了, 首先根据scale类型获取容器, 根据函数名获取地址, 根据参数个数获取函数类型, 最后执行.
所有的源代码我都上传在github上面, reflect
补充:
之前我一直以为该实现反射的方式只能在debug下才有效, 应为debug下编译器会玩可执行文件中加入大量的调试信息, 当使用release版本时, 并没有这些编译信息, 或许可以使用之前保存过的信息, 但可能会对内存地址有所影响. 之后我详细了解了elf文件格式后, 发现并不会影响, 至少我目前的测试是没有影响的. debug时是将调试信息以dwarf格式的段添加到可执行文件后, 而并不是随机穿插在程序中, 所以只有release时代码并没有修改, 注意宏的修改, 就可以使用debug时保存下来的调试信息.当我发现这个时有点小兴奋, 他解除了一个限制条件, 使得这种想法或许可以有更大的实用之处.
最后再说点什么:
这是自己第一次写博客, 自从上了大学以后, 没学过语文, 以前并不知道语文是这么重要, 直达现在发现自己并不能将自己想要说的流畅地, 有层次地表达出来, 写下来. 这几篇博客修修补补还是花了自己一点时间. 如果你在看完之后, 笑道这都写了写什么东西啊, 我也并不会介意的. 以前是懒与去经营自己的博客, 当发现自己写出属于自己的博客时, 还是挺有满足感的, 我也会继续写下去, 继续锻炼, 或许多年以后翻翻自己写过的东西, 回信一下自己当时的所思所想, 也将是已将很有趣的事情吧.
原文链接: https://www.cnblogs.com/YouJie/p/5333621.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/231158
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!