百度apollo源码学习(一) DEFINE_TYPE_TRAIT的理解

news/2024/11/28 7:30:47/

文章目录

  • 前言
  • 源码
    • 解读
    • SFINAE机制
    • 举例
  • 参考


前言

最近学习百度apollo源码,发现很多看不懂的代码,因才疏学浅,只能通过上网搜索,逐步理解,然后将理解完成的内容再次进行记录,其中参考了很多其他博主的博客。
我觉得对于程序员来说,看优秀的代码是进步最快的方式,看代码不仅要看懂代码,还要看明白设计者设计该部分代码的框架。
废话不多少,接下来看一下apollo中基于C++类型萃取实现的结构体成员变量或函数的存在性判断的宏定义:DEFINE_TYPE_TRAIT该宏定义位于:cyber/base/macros.h中。

源码

#define DEFINE_TYPE_TRAIT(name, func)                     \template <typename T>                                   \struct name {                                           \// 仅当T是一个类类型时,“Class::func”才是存在的,从而这个泛型函数的实例化才是可行的// 否则,就将触发SFINAEtemplate <typename Class>                             \static constexpr bool Test(decltype(&Class::func)*) { \return true;                                        \}                                                     \// 仅当触发SFINAE时,编译器才会“被迫”选择这个版本template <typename>                                   \static constexpr bool Test(...) {                     \return false;                                       \}                                                     \\static constexpr bool value = Test<T>(nullptr);       \};                                                      \\template <typename T>                                   \constexpr bool name<T>::value;

解读

这个宏定义创建了一个struct name的结构体constexpr bool name<T>::value的变量。
第6-15行使用了SFINAE机制,定义了模版类型的Test函数。具体参看【C++深陷】之“decltype”和C++模板SFINAE特性与反射机制

从名字可以知道这段代码的目的是定义一个名为name的类型萃取器,这个萃取器的name::value是bool类型,可以判定T中是否有func函数。使用如下:

DEFINE_TYPE_TRAIT(HasByteSize, ByteSizeLong)
//定义HasByteSize的结构体,func为ByteSizeLong

DEFINE_TYPE_TRAIT 会根据宏参数 name 创建一个同名的类型萃取模板类,并检查模板类型参数 T 中是否包含与宏参数 func 同名的方法,若包含,则模板类的 value 成员被置为 true,否则置为 false。应该注意的是,func 在 T 中必须是公有的,否则无法被发现。

所以 DEFINE_TYPE_TRAIT(HasByteSize, ByteSizeLong) 的具体含义是:创建类型萃取模板类 HasByteSize,HasByteSize可检查模板类型参数 T 中是否包含 ByteSizeLong方法。

HasByteSize<A>::value  \\ true 表示有A.ByteSizeLong()
//在宏定义中为name<T>::value,即HasByteSize.value, Test<T>(nullptr)
//这里的模版T就是A,那么4-7行Test模版中Class就是这里的A。
HasByteSize<B>::value  \\ false 表示没有B.ByteSizeLong()

其中A和B可以是结构体或者类。

SFINAE机制

C++模板提供了一个SFINAE(subsitate failure is not an error)的机制(模板匹配失败不是错误),这是模板里面一个非常有意思的特性,利用这个机制可以检查一个结构体是否包含某个成员等操作。c++语言本身没有提供反射机制(也有利用pb实现反射),利用SFINAE机制,可以实现类似于反射的功能。

举例

#include <cstdlib>
#include <iostream>
// A类型包含size函数
struct A {int size() {return 0;}
};
struct B {int Size() {return 1;}
};
// type trait
template <typename T>
struct HasSize {template <typename Class>static constexpr bool Test(decltype(&Class::size)*) {return true;}template<typename >static constexpr bool Test(...) {return false;}static constexpr bool value = Test<T>(nullptr);
};int main() {if (!HasSize<B>::value) {std::cout << "hello world" <<std::endl;}return 0;
}

上面代码中,HasSize中有静态的常量value,它的初值是通过调用结构体的静态成员函数Test(nullptr)来初始化的。
而它有两个Test函数,且都是constexpr修饰的,这表明函数参数及返回值在编译器就要确定下来。
正是如此,如果Class有size函数,那么

static constexpr bool Test(decltype(&Class::size)*) {return true;
}

在编译期就可以替换成功,即

static constexpr bool Test(Func *) {return true;
}

value = Test(nullptr)也就自然而然被初始化为true。否则,便会是false。
运行上述结果,因为B::size()不存在,可以看到最后输出了结果。

参考

【C++深陷】之“decltype”
C++模板SFINAE特性与反射机制
由一道C++面试题引发的思考
深入探索单例设计模式:以百度 Apollo 为例
C++ type_traits和SFINAE的一点理解


http://www.ppmy.cn/news/4085.html

相关文章

强调句句型

一、强调句句型&#xff1a; 1、用It is&#xff0f;was...that&#xff0f;who...句型表示强调。 &#xff08;1&#xff09;陈述句的强调句型&#xff1a;It is/was被强调部分&#xff08;通常是主语、宾语或状语&#xff09;that/who&#xff08;当强调主语且主语指人&#…

Pycharm SQL 警告:SQL dialect is not configured.

Pycharm SQL 警告&#xff1a;SQL dialect is not configured. 文章目录Pycharm SQL 警告&#xff1a;SQL dialect is not configured.Unable to resolve symbol XXX在我们编写python代码的时候&#xff0c;不免会在代码里面写入自己写的sql语句&#xff0c;因为很少有orm框架能…

大数据毕业设计人体跌倒检测系统

文章目录前言1 实现方法传统机器视觉算法基于机器学习的跌倒检测SVM简介SVM跌倒检测原理算法流程算法效果实现代码深度学习跌倒检测最终效果网络原理最后前言 背景和意义 在美国&#xff0c;每年在65岁以上老人中&#xff0c;平均每3人中就有1人发生意外跌倒&#xff0c;每年…

第八部分 make 的运行

一般来说&#xff0c;最简单的就是直接在命令行下输入 make 命令&#xff0c;make 命令会找当前目录的 Makefile 来执行&#xff0c;一切都是自动化的。但有时你只想让 make 重新编译某些文件而不是整个工程&#xff0c;或你有几套编译规则&#xff0c;你想在不同的时候使用不同…

Qt6 qtmqtt编译及演示示例(附带动态库)

前言 随着物联网的不断发展&#xff0c;如今很多项目都需要接入&#xff0c;而两年前也是因为项目需要&#xff0c;了解了一些关于mqtt的用法&#xff0c;并将其过程记录成几篇博客&#xff0c;近一年多时间陆陆续续有好多人私信咨询关于mqtt相关的问题&#xff0c;其中又有很…

牛客java刷题知识点总结(六)

内存引用地址 内存引用地址&#xff0c;是指栈中存放的地址&#xff0c;来指向堆中的某个位置。 int 是基本类型&#xff0c;数据直接存放在栈中&#xff0c;不存在内存引用地址的说法 A对 指向常量池里的"hello"。 B对 题中没说声明的a是局部变量。 C错 int a 1;并…

QT 学习笔记(九)

文章目录一、事件的接收和忽略1. 准备工作2. 接收和忽略二、event() 函数1. 简介2. 实例演示3. 总结三、事件过滤器四、总结&#xff08;细看&#xff09;1. 知识点汇总2. QT 的事件处理五、事件、事件的接收和忽略、event() 函数和事件过滤器代码1. 主窗口头文件 mywidget.h2.…

2023养老展,北京老博会,老年用品与适老家具展,老龄产业展

CBIAIE北京老博会的价值|引导社会关注老年人生活&#xff0c;助力老年产业发展&#xff0c;提升企业市场竞争力与美誉度&#xff1b; CBIAIE北京老博会&#xff1a;全称&#xff1a;中国&#xff08;北京&#xff09;国际老年产业博览会China (Beijing) International Aged in…