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

注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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/339161.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

html的页面宽高变形问题,CSS+div 设计的网页在不同浏览器中变形的问题

给别人做了一个web&#xff0c;自己这边正常&#xff0c;一到对方&#xff0c;机器上&#xff0c;发现变形了&#xff0c;真郁闷&#xff0c;后来才发现时IE7.0惹得祸&#xff0c;没有办法&#xff0c;学习呗。如何使网页在IE7.0和火狐中不变形&#xff1f;以下的方法可行&…

python爬虫开发 从入门到实战_python网络爬虫从入门到实战开发

1、简单的抓取网页 from urllib import request reqrequest.Request("http://www.baidu.com") responserequest.urlopen(req) htmlresponse.read() htmlhtml.decode("utf-8") print(html) 2、这里补充点Post和Get提交数据的差别 如果使用POST提交表单数据&…

swagger api文档_带有Swagger的Spring Rest API –公开文档

swagger api文档创建API文档后&#xff0c;将其提供给涉众很重要。 在理想情况下&#xff0c;此发布的文档将足够灵活以解决任何最后的更改&#xff0c;并且易于分发&#xff08;就成本以及完成此操作所需的时间而言&#xff09;。 为了使之成为可能&#xff0c;我们将利用我在…

html 页面重复度高,哪些情况容易造成重复页面

摘要在很多情况下我们明明没有发布重复页面&#xff0c;但为什么产生重复呢&#xff1f;下面我们一起来看看哪些情况容易造成重复页面&#xff1f;以及我们应该如何处理&#xff1f;abc.comabc.com/index.html在浏览器地址栏中输入这四个不同的URL链接&#xff0c;打在很多情况…

nuxt解决首屏加载慢问题_一个 Node 脚本让你的前端项目加载速度飞起来

写在最前面我的原创什么声明变成什么鬼了……前言随着前端三大框架的盛行&#xff0c;越来越多的前后端分离项目在服务器上跑了起来&#xff0c;随之而来&#xff0c;开发者也慢慢发现了这种开发模式所带来的弊端&#xff0c;其中之一就是首屏加载速度特别慢&#xff0c;因为虽…

数据库连接配置tomcat_Tomcat到Wildfly:配置数据库连接

数据库连接配置tomcat该摘录摘自《 从Tomcat到WildFly 》一书&#xff0c;您将在其中学习如何将现有的Tomcat体系结构移植到WildFly&#xff0c;包括服务器配置和在其顶部运行的应用程序。 WildFly是完全兼容的Java Enterprise Edition 7容器&#xff0c;与Tomcat相比&#xf…

左值、右值、左值引用、右值引用

【导读】&#xff1a;本文主要详细介绍了左值、右值、左值引用、右值引用以及move、完美转发。左值和右值左值&#xff08;left-values&#xff09;&#xff0c;缩写&#xff1a;lvalues右值&#xff08;right-values&#xff09;&#xff0c;缩写&#xff1a;rvalues直接上官网…

itex将html转成pdf加水印,itext操作PDF文件添加水印

功能描述&#xff1a;添加图片和文字水印/**** 【功能描述&#xff1a;添加图片和文字水印】 【功能详细描述&#xff1a;功能详细描述】* param srcFile 待加水印文件* param destFile 加水印后存放地址* param text 加水印的文本内容* param textWidth 文字横坐标* param tex…

wxpython界面切换_wxpython实现按钮切换界面的方法

本文实例为大家分享了wxpython按钮切换界面的具体实现代码&#xff0c;供大家参考&#xff0c;具体内容如下 #-*- coding:utf-8 -*- import wx class TestFrame(wx.Frame): def __init__(self): wx.Frame.__init__(self,None,-1,u登陆,size(370,280),stylewx.MINIMIZE_BOX| wx.…

jboss 4.3.0_JBoss BPM Suite 6.0.3版本的5个实用技巧

jboss 4.3.0上周&#xff0c;红帽发布了JBoss BPM Suite的下一个版本&#xff0c;标记为6.0.3 &#xff0c;已订阅的用户可以在其客户门户中使用。 如果您对本发行版中的新增功能感到好奇&#xff0c;请在客户门户网站上在线查看发行说明和其余文档 。 我们正在寻找一些简单的…

C 条件变量使用详解

condition_variable介绍在C 11中&#xff0c;我们可以使用条件变量&#xff08;condition_variable&#xff09;实现多个线程间的同步操作&#xff1b;当条件不满足时&#xff0c;相关线程被一直阻塞&#xff0c;直到某种条件出现&#xff0c;这些线程才会被唤醒。其主要成员函…

HTML5新布局元素布局,HTML5新的布局元素

HTML5相对于HTML4新增了一些布局元素新增布局标签的优点&#xff1a;⒈更加注重文档的结构内容而不是以什么形式展现出来⒉对人的友好&#xff0c;更加语义化&#xff0c;增加代码的可读性⒊对计算机友好&#xff0c;浏览器更容易解析新增布局标签的内容&#xff1a;新增的布局…

pannel添加的子窗体很大_超简单的地瓜粉焖子做法全解,零失败

总以为做焖子是一项很大的工程&#xff0c;如果朋友知道你会做焖子定会用惊叹的语气崇拜你&#xff0c;想多一项厨艺吗&#xff0c;想让家人吃上自己亲手做的焖子吗&#xff1f;使用艺琳农场的地瓜粉一定让你出手不凡的&#xff0c;超简单&#xff0c;往下看哦新手为了担心霍霍…

swagger api文档_带有Swagger的Spring Rest API –创建文档

swagger api文档使REST API易于使用的真正关键是好的文档。 但是&#xff0c;即使您的文档做得很好&#xff0c;您也需要设置公司流程的权利以正确&#xff0c;及时地发布它。 确保利益相关者按时收到是一回事&#xff0c;但是您也要负责API和文档中的更新。 自动完成此过程可轻…

多线程队列的算法优化

【导读】&#xff1a;本文主要讲解多线程队列的优化。多线程队列&#xff08;Concurrent Queue&#xff09;的使用场合非常多&#xff0c;高性能服务器中的消息队列&#xff0c;并行算法中的Work Stealing等都离不开它。对于一个队列来说有两个最主要的动作&#xff1a;添加&am…

购买台式计算机方案,购买电脑的注意事项有哪些?

随着电脑的应用与普及&#xff0c;电脑已经逐渐成为人们学习、工作、生活中不可缺少的工具。同时&#xff0c;电脑的价格在逐渐下降&#xff0c;很多用户开始准备选购自己的电脑。选购电脑要考虑用户的需求、价格承受能力、商家服务质量等。1、明确用户需求购买电脑之前&#x…

linux 文件大小_整理 | Linux下列出目录内容命令

IT服务圈儿有温度、有态度的IT自媒体平台来源&#xff1a;良许Linux(ID&#xff1a;liangxuxiansheng)在 Linux 中&#xff0c;有非常多的命令可以让我们用来执行各种各样的任务。当我们想要像使用文件浏览器一样列出一个目录下的内容时&#xff0c;大家第一时间想到的是 ls 命…

mysql caching_Spring Caching抽象和Google Guava Cache

mysql cachingSpring为缓存昂贵的方法调用提供了强大的现成支持。 这里详细介绍了缓存抽象。 我的目标是使用Spring Guava Cache涵盖Spring现在提供的4.0版本的较新的缓存实现之一。 简而言之&#xff0c;请考虑一种具有几种慢速方法的服务&#xff1a; public class DummyB…

多线程程序中操作的原子性

0. 背景原子操作就是不可再分的操作。在多线程程序中原子操作是一个非常重要的概念&#xff0c;它常常用来实现一些同步机制&#xff0c;同时也是一些常见的多线程Bug的源头。本文主要讨论了三个问题&#xff1a;1. 多线程程序中对变量的读写操作是否是原子的&#xff1f;2. 多…

2018秋计算机基础在线作业华师,18秋华师《计算机基础》在线作业3(标准答案).doc...

【奥鹏】[华中师范大学]华师《计算机基础》在线作业试卷总分:100 得分:100第1题,控制面板可实现__________。A、对计算机全面控制操作B、对硬件驱动、软件设置及Windows外观设置C、计算机的关闭操作D、删除计算机中的任意文件正确答案:B第2题,页眉和页脚的建立方法相似&#xf…