C++ 中的奇技淫巧大部分来源于模板技术,尤其是模版元编程技术(Template Meta-Programming, TMP)。TMP 通过将一部分计算任务放在编译时完成,不仅提高了程序的性能,还能让程序获得一些用常见语法结构无法实现的功能。在这里,我总结了几个利用 TMP 实现静态反射的例子,这些功能得益于模板的特化或模板实例化时的 SFINAE 行为。(代码默认包含 <iostream> 头)

1. 类型判定

#define MakeIsType(Tp) \
template <typename T> \
class Is_##Tp { \
public: \
enum {value = false}; \
}; \
template <> \
class Is_##Tp<Tp> { \
public: \
enum {value = true}; \
}; // 生成 Is_void 类
MakeIsType(void); int main(int argc, char const *argv[])
{
std::cout << Is_void<int>::value; //
std::cout << Is_void<void>::value; //
return ;
}

以上代码用了简单的特化,先定义一个 value 为 false 的基础类,并为 Tp 类特化一个 value 为 true 的模板。

2. 判定指针是否能转换

template <typename To, typename From>
class IsConvertable {
typedef char One;
typedef struct { One _[]; } Two; static One deduce(To*);
static Two deduce(...);
public:
enum { value = sizeof(deduce((From*))) == sizeof(One) };
}; int main() {
std::cout << IsConvertable<long int, long>::value; //
std::cout << IsConvertable<long int, double>::value; //
}

这里利用了成员函数的重载解析,如果 From 指针无法转换为 To 指针(无论是同类,还是子类转基类),那么第二个版本的 deduce 将被 sizeof 解析,完成判定的功能。( sizeof 并不会运行函数,但是会让编译器进行重载解析)

3. 成员名称检测

template <typename T>
class Has_foo {
typedef char One;
typedef struct { One _[]; } Two;
struct Base {
char foo;
};
struct Mixin : public T, public Base {};
template <typename U, U>
struct Matcher {};
template <typename U>
static One deduce(U*, Matcher<char Base::* ,&U::foo>* = );
static Two deduce(...);
public:
enum { value = sizeof(deduce((Mixin*))) == sizeof(Two) };
}; class A
{
public:
int foo(int, double);
}; class B
{
public:
int bar(int, double);
}; int main(int argc, char const *argv[]) {
std::cout << Has_foo<A>::value; //
std::cout << Has_foo<B>::value; //
return ;
}

这里用到了 SFINAE 技术,如果 A 含有 foo 成员,那么 Mixin 中就会有两个版本的 foo,一个来自 Base,一个来自 A,因为 Mixin 是一个多重继承的子类,调用 &U::foo 在 U 为 Mixin 时将会产生二义性,所以这个版本的 deduce 将不会产生。sizeof将解析到 Two 这个版本。

4. 成员函数(包含参数和返回值类型)检测

template<typename T, typename RESULT, typename ARG1, typename ARG2>
class HasMethod_foo
{
template <typename U, RESULT (U::*)(ARG1, ARG2)> struct Matcher;
template <typename U> static char deduce(Matcher<U, &U::foo> *);
template <typename U> static int deduce(...);
public:
enum { value = sizeof(deduce<T>()) == sizeof(char) };
}; class A
{
public:
int foo(int, double);
}; int main(int argc, char const *argv[]) {
std::cout << HasMethod_foo<A, int, int, int>::value; //
std::cout << HasMethod_foo<A, int, int, double>::value; //
return ;
}

这里采用了 SFINAE 技术,并利用了 C++ 中模板的非类型参数可以是成员指针这一性质,用一个 Matcher 类将 U 和某一类型的成员函数指针绑定在一起,如果一个类不存在这样的成员函数,那么第一个版本的 deduce 将无法生成。于是 sizeof 将解析到第二个版本。

结论

关于更多模板元编程的技术,可以参考 C++ Template 这本书。stackoverflow 也是一个获取这类奇技淫巧的好地方。

用 C++ 模板元编程实现有限的静态 introspection的更多相关文章

  1. 现代c++与模板元编程

    最近在重温<c++程序设计新思维>这本经典著作,感慨颇多.由于成书较早,书中很多元编程的例子使用c++98实现的.而如今c++20即将带着concept,Ranges等新特性一同到来,不得 ...

  2. C++ 模板元编程 学习笔记

    https://blog.csdn.net/K346K346/article/details/82748163 https://www.jianshu.com/p/b56d59f77d53 https ...

  3. C++模板元编程(C++ template metaprogramming)

    实验平台:Win7,VS2013 Community,GCC 4.8.3(在线版) 所谓元编程就是编写直接生成或操纵程序的程序,C++ 模板给 C++ 语言提供了元编程的能力,模板使 C++ 编程变得 ...

  4. C++模板元编程 - 函数重载决议选择工具(不知道起什么好名)完成

    这个还是基于之前实现的那个MultiState,为了实现三种类型“大类”的函数重载决议:所有整数.所有浮点数.字符串,分别将这三种“大类”的数据分配到对应的Converter上. 为此实现了一些方便的 ...

  5. C++模板元编程 - 挖新坑的时候探索到了模板元编程的新玩法

    C++真是一门自由的语言,虽然糖没有C#那么多,但是你想要怎么写,想要实现什么,想要用某种编程范式或者语言特性,它都会提供. 开大数运算类的新坑的时候(又是坑),无意中需要解决一个需求:大数类需要分别 ...

  6. 读书笔记_Effective_C++_条款四十八:了解模板元编程

    作为模板部分的结束节,本条款谈到了模板元编程,元编程本质上就是将运行期的代价转移到编译期,它利用template编译生成C++源码,举下面阶乘例子: template <int N> st ...

  7. c++ 模板元编程的一点体会

    趁着国庆长假快速翻了一遍传说中的.大名鼎鼎的 modern c++ design,钛合金狗眼顿时不保,已深深被其中各种模板奇技淫巧伤了身...论语言方面的深度,我看过的 c++ 书里大概只有 insi ...

  8. C++模板元编程 - 3 逻辑结构,递归,一点列表的零碎,一点SFINAE

    本来想把scanr,foldr什么的都写了的,一想太麻烦了,就算了,模板元编程差不多也该结束了,离开学还有10天,之前几天部门还要纳新什么的,写不了几天代码了,所以赶紧把这个结束掉,明天继续抄轮子叔的 ...

  9. C++模板元编程 - 2 模仿haskell的列表以及相关操作

    这是昨天和今天写的东西,利用C++的可变模板参数包以及包展开,模式匹配的一些东西做的,感觉用typename...比轮子叔那个List<A,List<B, List<C, D> ...

随机推荐

  1. 三、smarty--变量调节器(修改器)

    变量调节器(修改器) 作用: 1.  从PHP中分配个模板的变量 2.  需要模板中对变量在输出前进行处理 3.  处理方式就是使用“函数” 4.  在smarty3中可以直接调用到PHP的函数 5. ...

  2. dnSpy

    https://github.com/0xd4d/dnSpy 下载压缩包之后,解压,发现目录里面有3个exe文件 需要用管理员运行dnSpy.exe,然后打开exe文件,设置好断点,然后start 使 ...

  3. 浏览器端-W3School-JavaScript:JavaScript 全局对象

    ylbtech-浏览器端-W3School-JavaScript:JavaScript 全局对象 1.返回顶部 1. JavaScript 全局对象 全局属性和函数可用于所有内建的 JavaScrip ...

  4. ceph集群添加osd

    获取osd的ID 这个操作是在管理节点上执行 [root@node-4 osd]# ceph osd create 2 对磁盘做处理 [root@node-4 ~]# parted /dev/sdb ...

  5. 通过jenkins-Python在后台操作Jenkins构建job

    最近要开发1个接口,接收到1个指令后自动触发自动化测试,虽然也可以通过shell命令做这一步,但因为目前所有构建自动化的的动作都通过jenkins完成,所以想要尝试能不能用python去控制jenki ...

  6. [mysql]root用户登录mysql,输入密码后报错:Access denied for user 'root'@'localhost'

    问题如下: wangju-G4:~$ mysql -u root -p Enter password: ERROR (): Access denied for user 'root'@'localho ...

  7. 基于java config的springSecurity--session并发控制

    原作地址:http://blog.csdn.net/xiejx618/article/details/42892951 参考资料:spring-security-reference.pdf的Sessi ...

  8. Selenium 2自动化测试实战16(多窗口切换)

    一.多窗口切换 在页面操作过程中有时候点击某个链接会弹出新的窗口,这时就需要主机切换到新打开的窗口上进行操作.WebDriver提供了switch_to.window()方法.可以实现在不同的窗口之间 ...

  9. line-height 与 height 的区别

    line-height是行高的意思,它决定了元素中文本内容的高度,height则是定义元素自身的高度. height:表示  行高 line-height:表示   每行文字所占的高度   举例: 第 ...

  10. python3 selenuim PC端使用chrome模拟手机进行H5自动化

    情况说明:初次在做PC端使用chrome进行H5自动化测试时,以为和app端自动化一样使用click()就可以对按钮进行点击,找了好几天也没有找到解决方法,有些人说是工程问题,有些人是使用微信进行H5 ...