[翻译]More C++ Idioms - 类成员检测器

译注 - 需要注意的是如果是用VC编译器,直接使用__if_exist关键字就行了,不需要用这种方法:

__if_exist(Class::member)
{
    //do_something
}

__if_exist(Class::method)
{
    //do_something

目的

检测一个特定类成员的存在性。 

别称

动机

编译期的反射能力是C++模板元编程的基础。 诸如Boost.TypeTraits和TR1 <type_traits> header的类型特征(Type traits)库提供了强大的方法来分离类型和他们的关系的信息。检测一个类的数据成员的存在性也是编译期反射的一个例子。

解决方案和示例代码

成员检测器惯用法(idiom)通过"匹配失败不是错误"(Substitution Failure Is Not An Error-SFINAE)惯用法实现。下面的模板类DetectX<T>是一个可以检测类型T是不是有一个名为X的数据成员的元函数。注意数据成员X可以是任何类型。

template<typename T>
class DetectX
{
    struct Fallback { int X; }; // add member name "X"
    struct Derived : T, Fallback { };
 
    template<typename U, U> struct Check;
 
    typedef char ArrayOfOne[1];  // typedef for an array of size one.
    typedef char ArrayOfTwo[2];  // typedef for an array of size two.
 
    template<typename U> 
    static ArrayOfOne & func(Check<int Fallback::*, &U::X> *);
 
    template<typename U> 
    static ArrayOfTwo & func(...);
 
  public:
    typedef DetectX type;
    enum { value = sizeof(func<Derived>(0)) == 2 };
};
//(
typedef 
DetectX type; 这个并没有被用到,删掉这行也没有关系)

 

这个惯用法的工作原理是:在编译期创建一个可控的二义性并通过SFINAE惯用法最终从其中恢复过来。第一个代理类Fallback有一个名字和你想要检测存在性的成员一样的成员。类Derived多继承自TFallback,这样它将有至少一个名为X的成员,如果T也有一个数据成员X的话将会有两个。

模板结构体Check被用来创建一个可控的二义性。Check需要两个模板参数,第一个是类型参数,第二个是一个该类型的实例,例如Check<int, 5>就是一个有效地实例化
(译注:注意例子中用到了指向成员的指针(Pointers to Members)int Fallback::*。两个名为func的重载函数创建了一个重载集合,这是SFINAE惯用法的通常做法。第一个func函数只有在数据成员U::X可以被无二义性的取得的情况下会被实例化。而U::X的地址只有在类Derived中只有一个名为X的数据成员时可以被取得。也就是说,此时T不会有名为X的数据成员。如果T含有XU::X的地址在没有更多排除歧义的信息的情况下是没法取得的,因此在没有错误的情况下对第一个func的实例化将会失败而另一个同名函数将会被选择。你应该注意到了两个func函数的返回值类型是不同的。第一个函数返回一个大小为1的数组的引用而第二个函数返回一个大小为2的数组的引用。通过返回值大小的不同可以用来检测哪个函数被实例化了。最终,一个布尔值被暴露出来(译注:声明为public的一个枚举值,值为0或者1,可当为布尔值使用)。当返回值的sizeof结果为2时该值为true,也就是说,只有当因为T含有名为X的数据成员而导致第二个函数func被实例化时为true。

对每一个需要检测的不同的数据成员,上面的模板需要相应的变化。这时使用一个宏将是一个好办法。下面的示例代码说明了宏的使用方法:

#define CREATE_MEMBER_DETECTOR(X)                                                   \
template<typename T> class Detect_##X {                                             \
    struct Fallback { int X; };                                                     \
    struct Derived : T, Fallback { };                                               \
                                                                                    \
    template<typename U, U> struct Check;                                           \
                                                                                    \
    typedef char ArrayOfOne[1];                                                     \
    typedef char ArrayOfTwo[2];                                                     \
                                                                                    \
    template<typename U> static ArrayOfOne & func(Check<int Fallback::*, &U::X> *); \
    template<typename U> static ArrayOfTwo & func(...);                             \
  public:                                                                           \
    typedef Detect_##X type;                                                        \
    enum { value = sizeof(func<Derived>(0)) == 2 };                                 \
};
 
CREATE_MEMBER_DETECTOR(first);
CREATE_MEMBER_DETECTOR(second);
 
int main(void)
{
  typedef std::pair<intdouble> Pair;
  std::cout << ((Detect_first<Pair>::value && Detect_second<Pair>::value)? "Pair" : "Not Pair");

 检测被重载的成员函数

一个成员检测器惯用法的变体可以用来检测一个类中特定成员函数的存在性,即使这个函数被重载了(译注:不被重载的当然也行,因为检测时函数的参数类型可以作为模板参数传入,所以可以区分不同的重载)也能被检测到。

template<typename T, typename RESULT, typename ARG1, typename ARG2>
class HasPolicy
{
    template <typename U, RESULT (U::*)(ARG1, ARG2)> struct Check;
    template <typename U> static char func(Check<U, &U::policy> *);
    template <typename U> static int func(...);
  public:
    typedef HasMember type;
    enum { value = sizeof(func<T>(0)) == sizeof(char) }; 

};

//(typedef HasMember type; 似乎是个笔误,但是删掉这行也没有关系) 

 

上面的模板类HasPolicy检查U是否拥有一个名为policy的成员函数,该函数有两个参数ARG1ARG2,返回值为RESULT。模板结构体Check只有在U含有U::policy成员函数,该函数有两个参数ARG1ARG2并且返回RESULT时才会实例化成功。 注意模板结构体Check的第一个模板参数是一个类型,第二个模板参数是指向该类型的成员函数的指针。如果模板结构体Check不能被实例化,剩下的以int为返回值的func将会被实例化。func函数返回值类型的大小最终决定类型特征的答案:true或者false.

 

已知应用

相关惯用法

Substitution Failure Is Not An Error (SFINAE)

参考资料

Substitution failure is not an error, part II

原文链接

http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Member_Detector 

转载于:https://www.cnblogs.com/shawnhue/archive/2011/11/29/More_CPP_Idioms_Member_Detector.html

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

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

相关文章

联通、华为《5G室内覆盖》白皮书!

来源&#xff1a;5G摘要&#xff1a;近日&#xff0c;中国联通、华为联合发布了《面向5G的室内覆盖数字化演进白皮书》。干货报告未来智能实验室是人工智能学家与科学院相关机构联合成立的人工智能&#xff0c;互联网和脑科学交叉研究机构。未来智能实验室的主要工作包括&#…

JavaScript 执行机制

前端开发&#xff0c;一篇文章让你彻底搞懂&#xff0c;什么是JavaScript执行机制&#xff01;&#xff1a;https://zhuanlan.zhihu.com/p/139261821 大白话讲解 JavaScript 执行机制&#xff0c;一看就懂&#xff1a;https://www.jianshu.com/p/22641c97e351 JavaScript 运行…

MTK调试入门之一-TRACE使用的技巧

52RD上曾有朋友让我写一些调试技巧方面的文章.调试对于软件是十分重要的,但却不是一篇二篇文章能讲清楚的.有很多调试技巧都是零零碎碎的东西,用的时候能很容易使用,但要写出来时,却还是比较麻烦的. MTK的调试一般来说可以分为仿真调试与手机调试.这两种调试对于研发新功能,修改…

互联网大脑进化简史,华为云EI智能体加入-2018年7月新版

要&#xff1a;华为云EI智能体是2018年以来产生的第八个类脑智能巨系统&#xff0c;在中国&#xff0c;目前除了小米、联想、今日头条&#xff0c;几乎所有的互联网巨头都提出了自己的”大脑“系统建设计划。1969年互联网诞生以来&#xff0c;网状模型一直是互联网最基础和重要…

Windows 必备神器 Cmder 使用教程

From&#xff1a;终端利器Cmder&#xff1a;https://www.e-learn.cn/topic/3885768 1. 安装 Cmder 打开 Cmder官网&#xff08; https://cmder.net &#xff09;&#xff0c;下拉页面找到 Download 项选择下载&#xff0c;下载的时候&#xff0c;两个版本&#xff0c;分别是 mi…

T-SQL查询进阶--流程控制语句

概述 和其他高级语言一样&#xff0c;T-SQL中也有用于控制流程的语句。T-SQL中的流程控制语句进一步扩展了T-SQL的力量……使得大部分业务逻辑可以在数据库层面进行。但很多人对T-SQL中的流程控制语句并没有系统的了解&#xff0c;本篇文章会系统的对T-SQL语句中的流程控制语句…

潘建伟团队首次实现18个光量子比特纠缠,刷新世界记录

来源&#xff1a;澎湃网摘要&#xff1a;中国科学技术大学潘建伟教授及其同事陆朝阳、刘乃乐、汪喜林等通过调控六个光子的偏振、路径和轨道角动量三个自由度&#xff0c;在国际上首次实现18个光量子比特的纠缠&#xff0c;刷新了所有物理体系中最大纠缠态制备的世界纪录。中国…

Frida Hook 常用函数、java 层 hook、so 层 hook、RPC、群控

From&#xff1a;Frida hook 常用函数分享&#xff1a;https://www.52pojie.cn/thread-1196917-1-1.html From&#xff1a;Frida Hook Android 常用方法&#xff1a;https://blog.csdn.net/zhy025907/article/details/89512096 Frida 使用&#xff1a;https://zhuanlan.zhihu.c…

struts 1.2配置文件

struts 1.2配置文件 2011-07-19 19:59 49人阅读 评论(0) 收藏 举报 Struts中是apache组织的MVC框架 下表列出了Struts中用到的lib包及其用途 包名称 用途 Common-beanutils.jar 简单易用的 Java 反射和内省 API 包装器 Commons-collections.jar 一组用于扩展和增强 Java Collec…

资本|五大科技巨头并购投资布局分析

来源&#xff1a;199IT互联网数据中心就买进而言&#xff0c;科技巨头可能是一个理想的收购方。Alphabet、亚马逊、苹果、Facebook和微软拥有巨大的市场价值&#xff08;3.9万亿美元&#xff09;。综合来看&#xff0c;五大科技巨头在整个并购市场占有相对较小的份额。下图显示…

安装 Chrome 插件:Stylish、xStyle​、Tampermonkey、SwitchyOmega

安装 Chrome 插件 3 种方法 方法 1&#xff1a;直接通过 chrome 插件商店安装&#xff0c;google 插件商店因为 "都懂的" 原因无法访问&#xff0c;如果会 "高科技" 上网可以忽略。直接通过插件商店安装方法 2&#xff1a;如果不会 "高科技" 上网…

第2节 多层PCB设计布局和布线原则

11.2.1 元器件布局的一般原则 设计人员在电路板布局过程中需要遵循的一般原则如下。 &#xff08;1&#xff09;元器件最好单面放置。如果需要双面放置元器件&#xff0c;在底层&#xff08;Bottom Layer&#xff09;放置插针式元器件&#xff0c;就有可能造成电路板不易安放…

数据库管理工具 Navicat 和 DBeaver

Navicat “Navicat” 是一套可创建多个连接的数据库管理工具&#xff0c;用以方便管理 MySQL、Oracle、PostgreSQL、SQLite、SQL Server、MariaDB 和/或 MongoDB 等不同类型的数据库&#xff0c;并支持管理某些云数据库&#xff0c;例如阿里云、‎腾讯云。Navicat 和 Navicat …

百度Apollo发布中国首个自动驾驶安全报告,L3级别产品2020年量产上市

来源&#xff1a;雷锋网去年 10 月&#xff0c;全球自动驾驶研发先行者 Waymo 发布了长达 43 页的安全报告&#xff0c;里面详细说明了如何装备和训练自动驾驶车辆&#xff0c;从而避免驾驶过程中一些意外情况的发生。今年 1 月&#xff0c;美国车企巨头通用也发布了“2018 自动…

Chrome Devtools 高级调试指南

From ( Chrome Devtools 高级调试指南 )&#xff1a;https://juejin.cn/post/6844903961472974855 chrome devtools 设置黑色主题&#xff1a;https://blog.csdn.net/sinat_15347975/article/details/81151342 Chrome DevTools 实用技巧大全&#xff08;收藏&#xff09;&…

包揽全球50%以上份额,中美发力超级计算

来源&#xff1a;第一财经摘要&#xff1a;中国已经成为全球拥有最多超级计算机的国家。根据上周发布的一份最新榜单&#xff0c;全球排名前500强的超级计算机中&#xff0c;有206台是中国研制的&#xff1b;而美国仅拥有124台。多年来&#xff0c;美国长期主导着超级计算机市场…

Oracle函数translate()的用法

一、语法&#xff1a; TRANSLATE(string,from_str,to_str) 二、目的 返回将&#xff08;所有出现的&#xff09;from_str中的每个字符替换为to_str中的相应字符以后的string。TRANSLATE 是 REPLACE 所提供的功能的一个超集。如果 from_str 比 to_str 长…

Fiddler 抓包工具总结

From&#xff1a;https://www.cnblogs.com/yyhh/p/5140852.html 官方文档&#xff1a;https://www.telerik.com/support/fiddler Fiddler 调式使用 (一) --- 深入研究&#xff1a;https://www.cnblogs.com/tugenhua0707/p/4637771.html Fiddler 实战 --- 深入研究(二)&#…

Cassandra集群配置

版本&#xff1a;apache-cassandra-1.0.6机器1:10.16.233.27机器2:10.16.233.41机器3:10.16.233.45机器4:10.16.233.36机器5:10.16.233.39机器6:10.16.233.66机器1和机器2作为seed_providerjava jdk已经安装并且设置过JAVA_HOMEssh已经设置1.解压 apache-cassandra-1.0.6-bin.t…

云计算行业报告:2018, 风起云涌

来源&#xff1a;物联网智库摘要&#xff1a;依托弹性扩展、费用低、速度快的优势&#xff0c;云计算颠覆了传统IT架构&#xff0c;未来将成为主流的IT架构。多优势助力云计算颠覆传统IT服务架构经过十几年的发展&#xff0c;云计算已经形成了较为完善的生态系统&#xff0c;构…