C++霧中風景18:C++20, 從concept開始

轉(zhuǎn)眼間私痹,C++20的標準已經(jīng)發(fā)布快兩年了踢星。不少C++的開源項目也已經(jīng)將標準升級到最新的C++20了,筆者也開啟了新標準的學(xué)習歷程了表牢。所以借這系列的博文窄绒,記錄下筆者學(xué)習新標準的一些心得與吐槽~~
作為C++20系列的第一篇開篇之文,就要從千呼萬喚始處理的concept聊起了崔兴,后續(xù)很多新的feature的實現(xiàn)彰导,也仰賴新的concept的實現(xiàn),后續(xù)筆者的文章也會逐步展開敲茄。OK位谋,開始我們C++20旅程的第一站:concept

1.First Look

先從一個群友的一個實際的問題出發(fā),我們來看看concept可以解決什么問題堰燎。是怎么樣通過coding實現(xiàn)的掏父。

群里的一個問題

  • SFINAE
    熟悉C++模板編程的小伙伴肯定第一時間想到通過SFINAE的方式來解決,讓筆者來解決這個問題的話秆剪,會寫出下面的代碼:
template <typename T>
T test(T a) {
    static_assert(!std::is_same_v<void, decltype(a + a)>);
    static_assert(!std::is_same_v<void, decltype(a - a)>);
    static_assert(!std::is_same_v<void, decltype(a * a)>);
    static_assert(!std::is_same_v<void, decltype(a / a)>);
    return a;
}

這里寫的代碼是一個略微Trick的表達赊淑,利用decltype去獲取操作符計算后的類型,然后用std::is_same_v進行一個其實沒什么意義的類型比較仅讽,來滿足static_assert的語義陶缺,最終滿足我們對模板類型T的一些約束。

  • concept
    顯然上面的方式是很不直觀的洁灵,雖然能達到咱們的目的饱岸,但是從代碼優(yōu)雅角度來說是一種較差的選擇實現(xiàn)。

我們來看一下用C++20提供給我們的Concept是如何解決這個問題的:

template <typename T>
concept Cal = requires (T a) {
    a + a;
    a - a;
    a * a;
    a / a;
};

template <typename T>
requires Cal<T>
T test(T a) {
    return a;
}

這是通過concept來實現(xiàn)的一個類型約束方式徽千,Cal代表著一個concept的實現(xiàn)苫费,requires中花括號的內(nèi)容就代表了對于類型T的約束,要滿足下面的操作符

a + a;
a - a;
a * a;
a / a;

Bingo罐栈! 似乎C++20給了我們一個更好的trait黍衙,接著往下看,我們繼續(xù)來細探Concept的實現(xiàn)荠诬。

2. How to use

  • concept的定義

這里寫了一個例子琅翻,咱們基于這個例子來展開:

template <typename T>
concept Cal = requires (T a) {
    a + a;
    typename T::type;
   {a + a} -> std::same_as<float>;
    require  Concept2<T>;
};

這里定義了4個requires的要求,只有滿足這4個條件才能通過concept的限制柑贞,正常進行編譯方椎。

1). a + a這個是最簡單的,該表達式能通過編譯則代表符合要求钧嘶,這里不會進行實際的計算棠众。
2). typename T::type代表需要,T類型定義了type類型,才符合要求
3). {a + a} -> std::same_as<float> 這里的{}代表了decltype(a + a)之后的類型需要滿足后面的concept的需求闸拿。這是一個語法糖空盼,也可以通過這樣來實現(xiàn):requires std::is_floating_point_v<decltype(a + a)>
4). 最后的require Concept2<T>這代表了concept的嵌套邏輯。requires后面可以帶任意的concept

  • concept的使用

了解了concept定義之后新荤,我們就可以利用concept來進行模板類型的約束了揽趾。
這里“回字有四種寫法”,大家可以選擇自己喜歡的方式來使用苛骨。(真搞不懂搞這么多寫法干什么篱瞎,不能統(tǒng)一一下嗎?痒芝, 下面介紹的順序隨筆者的偏好以此遞減)

template<typename T> 
requires Cal<T>
T test(T a)
{
    return a + a;
}

1). 這是筆者最認可的一種書寫方式俐筋,語義明確,在模板類型定義之后明確對它的要求严衬。

template<Cal T> 
T test(T a)
{
    return a + a;
}

2). 也還行吧澄者,模板參數(shù)前指定了concept,也比較明確直觀瞳步。

Cal test(Cal a)
{
    return a + a;
}

3). concept命名一長就顯得有些瑣碎了闷哆,并且把concept當類型使用了,看起來有些怪異了单起。

template<typename T> 
T test(T a) requires Cal<T>
{
    return a + a;
}

4). 把concept寫后面的都是異端,當然如果你喜歡的話劣坊,也ok嘀倒。

3. concept的本質(zhì)

concept本質(zhì)上是:一個可以套用在模板上的constexpr bool值。

相信下面這段代碼能幫助你更好的理解它:

template <typename T>
concept Con = std::is_floating_point_v<T>;

int main(int argc, char* argv[]) {
    static_assert(std::is_same_v<decltype(Con<float>), bool>);
    std::cout << Con<int> << std::endl;
    return 0;
}

顯然局冰,上面的代碼我們用is_same_v確定了concept生成的類型就是bool類型测蘑。而同樣的,在運行期康二,咱們也可以將concept的結(jié)果作為一個bool常量進行使用碳胳,并打印。

所以沫勿,take it easy挨约。 concept很簡單,它只是C++20給你提供的一個better的工具产雹,來擺脫被瘋狂的模板報錯所支配的恐懼诫惭。但即使你完全不了解它,使用老的方式蔓挖,依然能夠同樣解決問題夕土。

4.小結(jié)

C++的一些模板推斷的錯誤常常讓人抓狂。而很多時候我們使用它需要

  • 要進行模板推斷類型的編程設(shè)計
  • 利用SFINAE的方式來類型約束

這無形之中增加Coding時的心智成本瘟判,而concept作為一個新的語法糖怨绣,給了我們拆分二者的機會:讓上帝歸上帝角溃,凱撒歸凱撒
使用好concept來進行類型約束篮撑,enjoy新標準帶來的便利吧减细。

希望大家能夠有所收獲,筆者水平有限咽扇。成文之處難免有理解謬誤之處邪财,歡迎大家多多討論,指教质欲。

5.參考資料

CppReference

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末树埠,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子嘶伟,更是在濱河造成了極大的恐慌怎憋,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件九昧,死亡現(xiàn)場離奇詭異绊袋,居然都是意外死亡,警方通過查閱死者的電腦和手機铸鹰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門癌别,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蹋笼,你說我怎么就攤上這事展姐。” “怎么了剖毯?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵圾笨,是天一觀的道長。 經(jīng)常有香客問我逊谋,道長擂达,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任胶滋,我火速辦了婚禮板鬓,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘镀钓。我一直安慰自己穗熬,他們只是感情好,可當我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布丁溅。 她就那樣靜靜地躺著唤蔗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上妓柜,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天箱季,我揣著相機與錄音,去河邊找鬼棍掐。 笑死藏雏,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的作煌。 我是一名探鬼主播掘殴,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼粟誓!你這毒婦竟也來了奏寨?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤鹰服,失蹤者是張志新(化名)和其女友劉穎病瞳,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體悲酷,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡套菜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了设易。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片逗柴。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖顿肺,靈堂內(nèi)的尸體忽然破棺而出嚎于,到底是詐尸還是另有隱情,我是刑警寧澤挟冠,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站袍睡,受9級特大地震影響知染,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜斑胜,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一控淡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧止潘,春花似錦掺炭、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春者冤,著一層夾襖步出監(jiān)牢的瞬間肤视,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工涉枫, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留邢滑,地道東北人。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓愿汰,卻偏偏與公主長得像翩迈,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子赤套,可洞房花燭夜當晚...
    茶點故事閱讀 45,515評論 2 359

推薦閱讀更多精彩內(nèi)容