999精品在线视频,手机成人午夜在线视频,久久不卡国产精品无码,中日无码在线观看,成人av手机在线观看,日韩精品亚洲一区中文字幕,亚洲av无码人妻,四虎国产在线观看 ?

基于C++17的泛型函數(shù)容器實現(xiàn)方法研究

2019-07-03 02:31:14閔軍羅泓
軟件工程 2019年5期

閔軍 羅泓

摘? 要:泛型函數(shù)容器的使用可以解耦對象之間的調(diào)用關(guān)系,有利于實現(xiàn)高內(nèi)聚、低耦合的軟件設(shè)計原則。C++標準庫中并沒有這樣的容器,用C++舊標準實現(xiàn)也很困難、很低效。C++1x等新標準發(fā)布后,出現(xiàn)了一些更好的實現(xiàn)方式。本文將在已有設(shè)計的基礎(chǔ)之上,基于C++17新標準,利用if constexpr、fold expression、std::invoke等新技術(shù),提供一種泛型函數(shù)容器的實現(xiàn)方式。測試表明該實現(xiàn)方式簡潔高效,解決了重載函數(shù)和某些特殊函數(shù)的注冊調(diào)用問題,可以顯著降低耦合性、提高代碼復(fù)用性。

關(guān)鍵詞:C++17;泛型;函數(shù)容器;高內(nèi)聚;低耦合

中圖分類號:TP311.1? ? ?文獻標識碼:A

Abstract:The application of generic function containers can decouple the calling relationships between objects,conducive to the realization of high cohesion and low coupling software design principles.There is no such container in the C++ standard library,and it is very difficult and inefficient to implement with the old C++ standard.The release of new standards,such as C++1x,has brought some better implementation methods.This paper provides a generic function container implementation method based on the existing design and the new C++17 standard,via some new technologies such as if constexpr,fold expression,and std::invoke.Test results show that the simple and efficient implementation method effectively solves the problem of registration and calling of overloaded functions and some special functions,significantly reducing coupling and improving code reusability.

Keywords:C++17;generic;function container;high aggregation;low coupling

1? ?引言(Introduction)

高內(nèi)聚、低耦合是軟件設(shè)計的基本原則,泛型函數(shù)容器的使用可以解耦對象之間的調(diào)用關(guān)系,有利于實現(xiàn)軟件設(shè)計的這一基本原則[1]。作為一種萬能函數(shù)注冊器,泛型函數(shù)容器可以將任意類型的函數(shù)用一個key進行注冊以供其他程序調(diào)用,可以注冊普通函數(shù)、函數(shù)模板、成員函數(shù)、函數(shù)對象、lambda表達式、重載函數(shù)和某些特殊函數(shù)等。當(dāng)全局函數(shù)或?qū)ο笾g存在交互調(diào)用需求時,比如需要相互調(diào)用對方成員函數(shù)或者不適合關(guān)聯(lián)的無關(guān)對象之間需要調(diào)用其他對象的成員函數(shù)或者全局函數(shù)需要調(diào)用成員函數(shù)等類似需求時,我們便可以將需要被調(diào)用的函數(shù)用一個key注冊起來以供其他實體調(diào)用。函數(shù)的調(diào)用者不必知道被調(diào)用者,二者都依賴于中間的泛型函數(shù)容器,借此便可以解耦對象之間的調(diào)用關(guān)系[2]。

C++標準庫中并沒有現(xiàn)存的泛型函數(shù)容器,用C++舊標準實現(xiàn)也很困難、很低效[3]。C++11、C++14、C++17等新標準發(fā)布后,出現(xiàn)了一些更好的實現(xiàn)方式。本文便是在已有設(shè)計的基礎(chǔ)之上,基于C++17新標準,利用if constexpr、fold expression、std::invoke等新技術(shù),提供一種泛型函數(shù)容器的實現(xiàn)方式[4,5]。

2? 泛型函數(shù)容器的結(jié)構(gòu)設(shè)計(Design of genericfunction container structure)

泛型函數(shù)容器的基本結(jié)構(gòu)與C++ STL中的容器類似。在把各種不同類型的函數(shù)存入容器時必須轉(zhuǎn)換為統(tǒng)一的數(shù)據(jù)結(jié)構(gòu),通過一個key進行注冊,此后用戶便可以借助這個key和必要信息提取已注冊的記錄來執(zhí)行該函數(shù),從而實現(xiàn)泛型函數(shù)容器的基本功能。

2.1? ?泛型函數(shù)容器的結(jié)構(gòu)圖

2.2? ?函數(shù)存取結(jié)構(gòu)的設(shè)計

由于泛型函數(shù)容器需要存取各種不同類型的函數(shù),具體包括普通函數(shù)、函數(shù)模板、成員函數(shù)、函數(shù)對象、lambda表達式、重載函數(shù)和某些特殊函數(shù)等,所以需要抽象出能夠區(qū)分各種不同函數(shù)的標志特征:函數(shù)簽名(Function Signature)。類似于用簽名可以識別不同人一樣,通過函數(shù)簽名便可以識別不同的函數(shù)[6]。從便于注冊和提取的角度,本項目主要關(guān)注函數(shù)簽名的四個部分:函數(shù)名f、函數(shù)所屬對象的指針pObj、參數(shù)包指針pArgsList、返回值指針pRet。若是成員函數(shù),pObj必須明確賦值,否則就必須賦值為空指針nullptr。

然后設(shè)計一個函數(shù)封裝類invoker,用來保存注冊函數(shù)的函數(shù)簽名。Fun是注冊函數(shù)的具體類型(包含函數(shù)簽名),每注冊一個函數(shù)就創(chuàng)建一個以模板參數(shù)Fun區(qū)分的該類對象,每個不同對象保存了注冊函數(shù)的函數(shù)簽名(包含四個部分),調(diào)用時便可以從中提取函數(shù)簽名來執(zhí)行該函數(shù)。

2.3? ?函數(shù)注冊和提取部分的設(shè)計

函數(shù)注冊時需要完整保存函數(shù)簽名各個部分的信息,不過調(diào)用時并不需要用戶提供完整的函數(shù)簽名。為了簡化調(diào)用方式,函數(shù)調(diào)用時用戶只需輸入函數(shù)參數(shù)列表和返回值類型即可,若是無返回值函數(shù)則只需輸入函數(shù)參數(shù)列表(可以理解為返回值為void類型)。按照以上設(shè)計思路,注冊函數(shù)時需要完整保存函數(shù)簽名的四個部分,調(diào)用函數(shù)時用戶只需輸入兩個參數(shù)即可。因此,設(shè)計注冊函數(shù)reg_fun時需要有四個參數(shù),設(shè)計調(diào)用函數(shù)call時只需有兩個參數(shù)即可。具體實現(xiàn)可參見后面完整代碼中的reg_fun、call。

3? 關(guān)鍵數(shù)據(jù)成員m_mapInvoker的設(shè)計(Design of the key data member m_mapInvoker)

3.1? ?關(guān)鍵數(shù)據(jù)成員m_mapInvoker保存的是key與函數(shù)的成對記錄

我們可以使用std::map容器來保存泛型函數(shù)容器的注冊數(shù)據(jù)。在本項目中,關(guān)鍵數(shù)據(jù)成員m_mapInvoker便是用于保存key與函數(shù)成對記錄的std::map容器。m_mapInvoker的key字段為std::string類型,是用戶指定名稱或者返回值及參數(shù)類型名稱的累加字符串;data字段則是std::function類模版封裝的特殊函數(shù)類型[7]。

若用戶注冊時指定了注冊名稱便以此為該條記錄的key,此時的key用std::string類型,不至于產(chǎn)生混淆。不過在調(diào)用該注冊函數(shù)時,若直接使用std::string類型的key,便可能與參數(shù)類型產(chǎn)生混淆,因為注冊函數(shù)的第一個參數(shù)也可能是std::string類型。所以,在調(diào)用該注冊函數(shù)時,必須使用key_fun類型的key,才能避免可能發(fā)生的混淆。fun_key是只含一個數(shù)據(jù)成員std::string key的簡單封裝類型,其主要作用就是在調(diào)用時避免與函數(shù)參數(shù)發(fā)生混淆。

若用戶注冊時未指定注冊名稱,便使用返回值及參數(shù)類型名稱的累加字符串作為該條記錄的key,提取時也會自動生成返回值及參數(shù)類型名稱的累加字符串作為key來查詢調(diào)用該注冊函數(shù)。這樣的設(shè)計,同時也解決了參數(shù)列表相同、返回值不同的多個函數(shù)的注冊調(diào)用問題。

m_mapInvoker的data字段用于保存函數(shù)簽名的四個部分,它是以std::function類模版封裝的特殊函數(shù)void(void*,void*)。該封裝函數(shù)無返回值,第一個參數(shù)為注冊函數(shù)的參數(shù)包指針,第二個參數(shù)為注冊函數(shù)的返回值指針。

具體實現(xiàn)可以參見完整代碼中的fun_key類(其結(jié)構(gòu)參見圖2)、call_impl、get_key_from_fun_args等函數(shù),以及后面的測試代碼。

3.2? ?封裝函數(shù)的原始模型

關(guān)鍵數(shù)據(jù)成員m_mapInvoker的data字段中保存的并非單純的封裝函數(shù),而是通過std::bind綁定到原始函數(shù)模型上的間接函數(shù)[8]。封裝函數(shù)的原始模型是invoker::apply(…),F(xiàn)un是注冊函數(shù)的函數(shù)類型(包含函數(shù)簽名),Object是注冊函數(shù)所屬的對象類型(若是非成員函數(shù)則為void)。原始函數(shù)invoker::apply(…)有四個參數(shù),分別用于關(guān)聯(lián)注冊函數(shù)類型(函數(shù)簽名)的四個部分:函數(shù)名f、成員函數(shù)的對象指針pObj、參數(shù)包指針_1、返回值指針_2。_1、_2為C++11新標準的占位符[9],是用戶在提取記錄調(diào)用注冊函數(shù)時需要輸入的參數(shù),若注冊函數(shù)無返回值,則只需輸入第一個參數(shù)即可。具體可以參見后面的完整代碼。

3.3? ?解決重載函數(shù)和某些特殊函數(shù)的注冊調(diào)用問題

在以上設(shè)計的泛型函數(shù)容器中,若直接注冊存在兩個以上實例的重載函數(shù),編譯時就會報錯。解決該問題的思路很簡單,就是針對重載函數(shù)的多個實例對應(yīng)地定義多個不同名稱和類型的函數(shù)指針、并將重載函數(shù)賦值給它們,這就相當(dāng)于將多個重載函數(shù)的實例轉(zhuǎn)換成為多個不同名稱和類型的新函數(shù)指針。使用這些新的函數(shù)指針便能在泛型函數(shù)容器中成功進行注冊和調(diào)用。另外,也可以用lambda表達式來消除重載函數(shù)的二義性[10]。對某些特殊函數(shù)的處理也類似,包括特殊函數(shù)1:參數(shù)列表相同、返回值不同的多個函數(shù)的注冊和調(diào)用,這在本項目設(shè)計中已經(jīng)解決;特殊函數(shù)2:參數(shù)列表相同、返回值相同的多個函數(shù)的注冊和調(diào)用,可以用lambda表達式封裝該函數(shù),增加一個參數(shù)即可。具體請參見后面的測試代碼。

4? ?利用C++17新技術(shù)優(yōu)化代碼設(shè)計(Optimize code design with C++17 new technology)在本項目中,使用了C++17的if constexpr[11]新技術(shù)在編譯期進行判斷,去除enable_if_t,合并許多功能類似的函數(shù)。包括:合并非成員函數(shù)、成員函數(shù)注冊的兩種reg_fun函數(shù);合并有返回值、無返回值的兩種call函數(shù);合并Key與fun_key類型相同和不同的兩種call_impl、get_key_from_fun_args函數(shù)等。

在C++17之前,我們經(jīng)常用逗號表達式和std::initializer_list將變參依次傳入一個函數(shù)。用C++17的fold expression折疊表達式代替initializer_list,就要簡潔得多[12]。本項目便使用了C++17的這一新技術(shù)簡化代碼設(shè)計。

利用C++17的invoke調(diào)用器,可以合并非成員函數(shù)、成員函數(shù)的調(diào)用,統(tǒng)一使用std::invoke(f,pArgsList)這種簡捷形式進行調(diào)用[13]。當(dāng)然,成員函數(shù)調(diào)用時,對象實例必須放在 pArgsList的首位,作為第一個參數(shù)。在本項目中,便使用了C++17的這一新技術(shù)簡化代碼設(shè)計。

5? ?C++17泛型函數(shù)容器的完整實現(xiàn)代碼(Complete implementation code of C++17 generic function container)

5.1? ?泛型函數(shù)容器的完整實現(xiàn)代碼

以下便是本文介紹的泛型函數(shù)容器的完整實現(xiàn)代碼。用戶需要注意的是,以下代碼是基于C++17新標準實現(xiàn)的,需要在支持C++17的編譯器中才能夠正常編譯,比如Visual Studio 2017 15.3[14]、CodeBlocks 17.12 with GCC 7.2及以上版本[15]。

6? 泛型函數(shù)容器的實際使用(Actual use of generic function container)

下面代碼測試了泛型函數(shù)容器的實際使用。測試可以分為注冊函數(shù)時輸入key和未輸入key兩大類。每一大類都可以實現(xiàn)無返回值普通函數(shù)、帶返回值普通函數(shù)、函數(shù)模板、成員函數(shù)、函數(shù)對象、lambda表達式、重載函數(shù)、某些特殊函數(shù)等的注冊和調(diào)用。

6.1? ?實際使用的測試代碼

6.2? ?重載函數(shù)和某些特殊函數(shù)的注冊調(diào)用測試

前面已經(jīng)提到,本項目解決了重載函數(shù)和某些特殊函數(shù)的注冊調(diào)用問題。具體測試代碼如下。

7? ?結(jié)論(Conclusion)

綜上所述,泛型函數(shù)容器可以將任意類型的函數(shù)用一個key進行注冊以供其他程序調(diào)用,它的使用可以解耦對象之間的調(diào)用關(guān)系,有利于實現(xiàn)高內(nèi)聚、低耦合的軟件設(shè)計原則。C++標準庫中并沒有這樣的容器,用C++舊標準實現(xiàn)也很困難、很低效。C++1x等新標準發(fā)布后,出現(xiàn)了一些更好的實現(xiàn)方式。本文便是在已有設(shè)計的基礎(chǔ)之上,基于C++17新標準,利用if constexpr、fold expression、std::invoke等新技術(shù),提供一種泛型函數(shù)容器的實現(xiàn)方式。測試結(jié)果表明,該實現(xiàn)方式簡潔高效地實現(xiàn)了任意類型函數(shù)的注冊和調(diào)用,并且解決了重載函數(shù)和某些特殊函數(shù)的注冊調(diào)用問題,可以顯著降低耦合性、提高代碼復(fù)用性。

參考文獻(References)

[1] Ofenbeck G,Rompf T,Püschel M.Staging for generic programming in space and time[C].The ACM SIGPLAN International Conference.ACM,2017:15-28.

[2] Bemardi ML,Cimitile M,Lucca GD.Design pattem detection using a DSL-driven graph matching approach[J].Journal of Software Evolution&Process,2014,26(12):1233-1266.

[3] B Rasool G,Mader P.A customizable approach to design pattems recognition based 011 feature types[J].Arabian Journal for Science&Engineering,2014,39(12):8851-8873.

[4] Chen Yewang,Jiang Zhixiong,Zhao Wenyun,et al.Generic component:a generic programming approach[EB/OL].https://www.computer.org/csdl/proceedings/cit/2007/2983/00/29830087-abs.html,2018 IEEE.

[5] Yallop J.Staging,generic programming[M].New York:ACM,2016:85-96.

[6] 符號修飾(name decoration)與函數(shù)簽名(function signature)[EB/OL].https://blog.csdn.net/weiwangchao_/article/details/7165467,2011-12-30.

[7] std::function[EB/OL].https://en.cppreference.com/w/cpp/utility/functional/function,2018-06-15.

[8] Bjarne Stroustrup.The C++ Programming Language Fourth Edition[M].USA:Addison-Wesley Professional,2013:967.

[9] std::placeholders[EB/OL].https://en.cppreference.com/w/cpp/utility/functional/placeholders,2018-06-15.

[10] Stanley B,Lippman.C++ Primer 5th Edition[M].USA:Addison-Wesley Professional,2012:572-574.

[11] if statement,attr(optional)if constexpr(optional)(init-statement(optional)condition)statement-true else statement-false[EB/OL].https://en.cppreference.com/w/cpp/language/if,2018-08-21.

[12] Fold expression(since C++17)[EB/OL].https://en.cppreference.com/w/cpp/language/fold,2018-07-19.

[13] std::invoke[EB/OL].https://en.cppreference.com/w/cpp/utility/functional/invoke,2018-07-06.

[14] C++ conformance improvements in Visual Studio 2017 versions[EB/OL].https://docs.microsoft.com/en-us/cpp/cpp-conformance-improvements-2017?view=vs-2017,2018-08-15.

[15] C++ Standards Support in GCC[EB/OL].https://gcc.gnu.org/projects/cxx-status.html,2018-09-30.

[16] 獲得函數(shù)返回值類型、參數(shù)tuple、成員函數(shù)指針中的對象類型[EB/OL].https://www.cnblogs.com/ybmj/p/9651227.html,2018-09-15.

主站蜘蛛池模板: 国产成人亚洲日韩欧美电影| 欧美综合一区二区三区| 亚洲婷婷丁香| 日韩在线中文| 欧美日韩亚洲国产主播第一区| 国产波多野结衣中文在线播放| 重口调教一区二区视频| 99久久精品视香蕉蕉| 一级毛片免费高清视频| 成人免费网站久久久| 国产极品美女在线观看| 欧洲欧美人成免费全部视频| 亚洲一区二区无码视频| 激情无码视频在线看| 久久精品人人做人人综合试看| 欧美五月婷婷| 亚洲av日韩综合一区尤物| 国产精品99久久久| 国产丝袜无码精品| 美女黄网十八禁免费看| 国产无码制服丝袜| 91精品啪在线观看国产60岁| 国产精品久久久久无码网站| 午夜精品福利影院| 午夜日b视频| 日韩在线欧美在线| 青草国产在线视频| 首页亚洲国产丝袜长腿综合| 97超碰精品成人国产| 日韩精品一区二区深田咏美| 欧美日韩午夜视频在线观看| 九九热视频精品在线| 久久国语对白| 国产高清在线丝袜精品一区| 天天摸夜夜操| 久久综合丝袜长腿丝袜| 亚洲精品无码不卡在线播放| 免费观看国产小粉嫩喷水| 午夜国产小视频| 精品无码国产自产野外拍在线| 国内精品自在自线视频香蕉| 2020亚洲精品无码| 91小视频在线观看免费版高清| 日本黄色a视频| 亚洲精品国偷自产在线91正片| 天天视频在线91频| 色婷婷亚洲综合五月| 欧美激情首页| 亚洲一区二区三区麻豆| 曰AV在线无码| 九九九国产| 先锋资源久久| 国产aⅴ无码专区亚洲av综合网| 国产美女无遮挡免费视频| 永久免费av网站可以直接看的| 91国内视频在线观看| 欧美另类视频一区二区三区| 亚洲最新在线| 51国产偷自视频区视频手机观看 | 国产丝袜91| 四虎国产在线观看| 怡春院欧美一区二区三区免费| 亚洲人成网站在线播放2019| 中文字幕乱码中文乱码51精品| 乱系列中文字幕在线视频| 内射人妻无套中出无码| 婷婷亚洲天堂| 韩日午夜在线资源一区二区| 欧亚日韩Av| 成人亚洲天堂| 久久婷婷六月| 狠狠色成人综合首页| 五月六月伊人狠狠丁香网| 成人国产一区二区三区| 国产拍揄自揄精品视频网站| 亚洲视频免费在线| 亚洲精品动漫在线观看| 免费不卡视频| 亚洲欧美在线综合图区| 人妻丰满熟妇AV无码区| 性视频久久| 国产一级视频在线观看网站|