注1:本文至少需要编译器支持C 11。

注2:本文不考虑使用宏。

一、老办法

在写C 的时候,有时候可能需要检查一个类是否有特定的成员类型,例如:

// 检查 T::type 是否存在,存在则 value 为 true,否则为 falsetemplate <typename T>struct has_type;
struct A {};struct B { using type = int; };static_assert(!has_type::value, "Failed"); // 不存在static_assert(has_type::value, "Failed"); // 存在

或者需要检查一个类是否有特定的成员函数,例如:

// 检查 T.get() 是否存在,存在则 value 为 true,否则为 falsetemplate <typename T>struct has_get;
struct A {};struct B { int get() { return 42; } };static_assert(!has_get::value, "Failed"); // 不存在static_assert(has_get::value, "Failed"); // 存在

如果是在很久以前的 C 98 时代,可能会这样利用 SFINAE 实现:

template struct has_type {private:    typedef char one;    typedef struct { char data[2]; } two;    // 存在的话返回类型为 one    template  static one test(typename U::type*);    // 不存在的话返回类型为 two    template  static two test(...);public:    enum { value = sizeof(test(0)) == sizeof(one) };};

如果 T::type 存在的话就会选择第一个重载,否则就会选择第二个重载,由此判断 T::type 是否存在。但是这样的代码阅读起来可能会挺费劲的……于是,现在有了 void_t!

二、void_t

void_t<...> 其实就是 void,但它可以在 SFINAE 中帮助判断类型是否存在,示例如下:

template <typename T, typename = void>struct has_type : std::false_type {};template struct has_type<T, void_t> : std::true_type {};

(看起来是不是和 enable_if 的某种用法有相似之处?)

虽然 void_t 在 C 17 才成为标准库的一部分,但是我们可以在 C 11 中自己造一个:

template  struct make_void { using type = void; };template  using void_t = typename make_void::type;

需要注意的是上面的定义是为了兼容 C 11 / C 14 而这样写的,因为别名模板中未被使用的模板参数可能会被忽略。但如果是 C 17 的话,编译器就不能忽略别名模板中未被使用的模板参数,就可以直接这样写:

template using void_t = void;

(当然有 C 17 的话就能用标准库的 std::void_t 了……)

同理,我们也可以用同样的方式判断成员函数是否存在:

template <typename T, typename = void>struct has_get : std::false_type {};template struct has_get<T, void_t<decltype(std::declval().get())>> : std::true_type {};

三、Detection Idiom:is_detected

即使我们有了 void_t,但每次需要一个新的判定就得再撸一遍 SFINAE,依然有点不够直观(你说用宏?…… 我什么都没听到)。那么我们为什么不把这种判定也提炼成模板呢?有请 is_detected 出场——

template using has_type_t = typename T::type;template using has_type = is_detected;

看起来使用 is_detected 的方法比之前的 has_type 清爽多了吧,而且非常直观。

虽然 is_detected 还没有进入标准,但我们依然可以在 C 11 中把它造出来:

template <typename, template <typename...> class Op, typename... T>struct is_detected_impl : std::false_type {};template <template <typename...> class Op, typename... T>struct is_detected_impl<void_t<Op>, Op, T...> : std::true_type {};
template <template <typename...> class Op, typename... T>using is_detected = is_detected_impl;

如果仔细看的话,你就能够发现这就是给之前的方法加上了模板模板参数,使得它更容易使用。下面是用 is_detected 判断成员函数是否存在:

template using has_get_t = decltype(std::declval().get());template using has_get = is_detected;

当然,is_detected 还可以做到更多,只要你能够写出 Op 的话就有很多可以做的事情,比如说做各种 concept 的检查。除了 is_detected 之外,Detection Idiom 还有 detected_t 和 detected_or 等工具,可以用于在 trait 中实现默认类型,这里就不再展开介绍,感兴趣的话可以到上面的链接里看一下。

来源:https://zhuanlan.zhihu.com/p/2615546

如何优雅地检测类型/表达式有效性?相关推荐

  1. 亿愿批量验证检测网址链接有效性

    亿愿批量验证检测网址链接有效性(yyUrlValidate)-简介 ---最为专业的网址有效性验证工具!具备多线程和代理ip可限次数使用! ---三种技术验证网址有效性,多种有效性定义可以选用! -- ...

  2. 【编译原理笔记11】中间代码生成:类型表达式,声明语句的翻译

    本次笔记内容: 6-1 类型表达式 6-2 声明语句的翻译 本节课幻灯片,见于我的 GitHub 仓库:第11讲 中间代码生成_1.pdf 文章目录 类型表达式 Type Expression 举例 ...

  3. CoBOT Java安全漏洞检测类型与OWASP TOP 10对应关系

    OWASP(Open Web Application Security Project)开放式web应用程序安全项目,是一个非营利性组织,不依附于任何企业或财团的安全组织,几乎每隔3年发布的OWASP ...

  4. object的部分属性和方法 + 逗号操作符 + label语句 + with + switch + 参数 + typeof和instanceof检测类型 -- 大一下第十五周

    目录 object的一部分属性和方法 逗号操作符 label语句 with语句 switch语句 参数(原始值和引用值的区别) 检测类型 typeof instanceof 小记 valueOf() ...

  5. 低电压检测类型的电压检测器IC能否用作过电压检测使用?

    可以把电源电压恢复时的复位解除电压作为过电压检测电压使用. 但是,必须注意以下几种用法. <低压检测类型的电压检测器IC作为过电压检测使用时的注意事项> 使用时,电源电压即使瞬间也不能超过 ...

  6. 将整数k转换成实数python表达式_在混合类型表达式中python自动转换intlongfloat例如.ppt...

    在混合类型表达式中python自动转换intlongfloat例如 空位:格式指示符,描述了填入的值的输出形式. %. 类型字符: 宽度:用多少位置显示数值. 省略或指定为0:根据值的实际长度显示. ...

  7. GoLang之编译器自动检测类型是否实现接口(5)

    文章目录 GoLang之编译器自动检测类型是否实现接口(5) GoLang之编译器自动检测类型是否实现接口(5) 经常看到一些开源库里会有一些类似下面这种奇怪的用法: var _ io.Writer ...

  8. 如何使用Threatest测试端到端威胁检测规则的有效性

    关于Threatest Threatest是一个基于Go开发的安全测试框架,该框架可以帮助广大研究人员测试端到端威胁检测规则的有效性与可用性. Threatest允许我们使用各种渗透测试技术对目标进行 ...

  9. 《专家系统(开发)--表达式检测--与表达式模板一起使用》

    2019独角兽企业重金招聘Python工程师标准>>> <专家系统破解篇 九.Simple Rule Engine规则推理引擎三(表达式分析)> 表达式模板化配置的思路 ...

最新文章

  1. 一些有趣的题目(java)持续更新
  2. QEMU,一个快速的和便捷的动态翻译器(论文译文)
  3. 区别聚焦索引和非聚集索引
  4. c# 窗口句柄问题 。
  5. mfc中的.rc和.rc2出错fatal error RC1015: cannot open include file 'res\ModalD
  6. 【动态规划】最小代价问题
  7. mybatis学习笔记-04-常见错误排查
  8. NFT平台Polkamon将于3月31日在Polkastarter进行IDO
  9. 数据结构图之一(基本概念,存储结构,两种遍历)
  10. 目标检测综述——单阶段检测器
  11. Word转PDF方法(jacob插件)
  12. 论文的参考文献如何对齐。
  13. 计算机二进制除法除数为0,怎么做二进制数的除法运算
  14. 倍增设计技术(指针跳跃技术)——表序问题——求森林的根
  15. 非主流照片制作软件 Picasa有哪些主要的功能
  16. 孤岛惊魂3闪退win10win11下运行办法
  17. Java安卓如何添加悬浮窗_Android桌面悬浮窗效果实现
  18. 面临公司变相裁员该如何应对
  19. 第三届蓝桥杯JavaC组国(决)赛真题
  20. 【OpenCV】Ubuntu配置OpenCV环境

热门文章

  1. 用Java对HashMap排序
  2. 正确的工作流程:我应该使用哪个OAuth 2.0流程?
  3. .xhr长轮询_使用Spring 3.2的DeferredResult进行长轮询
  4. spring常见面试问题_Spring面试问题
  5. java集合提取最小的日期_提取Java集合的元素-Java 8方法
  6. Lombok,自动值和不可变项
  7. teamcity_TeamCity工件:HTTP,Ant,Gradle和Maven
  8. JDK 9:模块系统状态的重点
  9. datanucleus_DataNucleus 3.0与Hibernate 3.5
  10. gwt-2.8.2下载_GWT 2 Spring 3 JPA 2 Hibernate 3.5教程– Eclipse和Maven 2展示