日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

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

發(fā)布時間:2024/7/19 c/c++ 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [翻译]More C++ Idioms - 类成员检测器 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

譯注 - 需要注意的是如果是用VC編譯器,直接使用__if_exist關(guān)鍵字就行了,不需要用這種方法:

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

__if_exist(Class::method)
{
????//do_something

}?

目的

檢測一個特定類成員的存在性。?

別稱

動機

編譯期的反射能力是C++模板元編程的基礎(chǔ)。?諸如Boost.TypeTraits和TR1 <type_traits> header的類型特征(Type traits)庫提供了強大的方法來分離類型和他們的關(guān)系的信息。檢測一個類的數(shù)據(jù)成員的存在性也是編譯期反射的一個例子。

解決方案和示例代碼

成員檢測器慣用法(idiom)通過"匹配失敗不是錯誤"(Substitution Failure Is Not An Error-SFINAE)慣用法實現(xiàn)。下面的模板類DetectX<T>是一個可以檢測類型T是不是有一個名為X的數(shù)據(jù)成員的元函數(shù)。注意數(shù)據(jù)成員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; 這個并沒有被用到,刪掉這行也沒有關(guān)系)

?

這個慣用法的工作原理是:在編譯期創(chuàng)建一個可控的二義性并通過SFINAE慣用法最終從其中恢復(fù)過來。第一個代理類Fallback有一個名字和你想要檢測存在性的成員一樣的成員。類Derived多繼承自TFallback,這樣它將有至少一個名為X的成員,如果T也有一個數(shù)據(jù)成員X的話將會有兩個。

模板結(jié)構(gòu)體Check被用來創(chuàng)建一個可控的二義性。Check需要兩個模板參數(shù),第一個是類型參數(shù),第二個是一個該類型的實例,例如Check<int, 5>就是一個有效地實例化 (譯注:注意例子中用到了指向成員的指針(Pointers to Members)int Fallback::*)。兩個名為func的重載函數(shù)創(chuàng)建了一個重載集合,這是SFINAE慣用法的通常做法。第一個func函數(shù)只有在數(shù)據(jù)成員U::X可以被無二義性的取得的情況下會被實例化。而U::X的地址只有在類Derived中只有一個名為X的數(shù)據(jù)成員時可以被取得。也就是說,此時T不會有名為X的數(shù)據(jù)成員。如果T含有X,U::X的地址在沒有更多排除歧義的信息的情況下是沒法取得的,因此在沒有錯誤的情況下對第一個func的實例化將會失敗而另一個同名函數(shù)將會被選擇。你應(yīng)該注意到了兩個func函數(shù)的返回值類型是不同的。第一個函數(shù)返回一個大小為1的數(shù)組的引用而第二個函數(shù)返回一個大小為2的數(shù)組的引用。通過返回值大小的不同可以用來檢測哪個函數(shù)被實例化了。最終,一個布爾值被暴露出來(譯注:聲明為public的一個枚舉值,值為0或者1,可當(dāng)為布爾值使用)。當(dāng)返回值的sizeof結(jié)果為2時該值為true,也就是說,只有當(dāng)因為T含有名為X的數(shù)據(jù)成員而導(dǎo)致第二個函數(shù)func被實例化時為true。

對每一個需要檢測的不同的數(shù)據(jù)成員,上面的模板需要相應(yīng)的變化。這時使用一個宏將是一個好辦法。下面的示例代碼說明了宏的使用方法:

#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<int,?double>?Pair;
??std::cout?<<?((Detect_first<Pair>::value?&&?Detect_second<Pair>::value)??"Pair"?:?"Not?Pair");

}?

?檢測被重載的成員函數(shù)

一個成員檢測器慣用法的變體可以用來檢測一個類中特定成員函數(shù)的存在性,即使這個函數(shù)被重載了(譯注:不被重載的當(dāng)然也行,因為檢測時函數(shù)的參數(shù)類型可以作為模板參數(shù)傳入,所以可以區(qū)分不同的重載)也能被檢測到。

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; 似乎是個筆誤,但是刪掉這行也沒有關(guān)系)?

?

上面的模板類HasPolicy檢查U是否擁有一個名為policy的成員函數(shù),該函數(shù)有兩個參數(shù)ARG1和ARG2,返回值為RESULT。模板結(jié)構(gòu)體Check只有在U含有U::policy成員函數(shù),該函數(shù)有兩個參數(shù)ARG1和ARG2并且返回RESULT時才會實例化成功。 注意模板結(jié)構(gòu)體Check的第一個模板參數(shù)是一個類型,第二個模板參數(shù)是指向該類型的成員函數(shù)的指針。如果模板結(jié)構(gòu)體Check不能被實例化,剩下的以int為返回值的func將會被實例化。func函數(shù)返回值類型的大小最終決定類型特征的答案:true或者false.

?

已知應(yīng)用

相關(guān)慣用法

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?

轉(zhuǎn)載于:https://www.cnblogs.com/shawnhue/archive/2011/11/29/More_CPP_Idioms_Member_Detector.html

總結(jié)

以上是生活随笔為你收集整理的[翻译]More C++ Idioms - 类成员检测器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。