Modern C++ std::any為何要求Tp可拷貝構造?

小問題也會影響設計的思路,某個問題或某種case的探討有助于理解設計的初衷。

聲明:以下_Tp/Tp都是指要放入std::any的對象的類型。

它要求_Tp?is_copy_constructible, 僅僅是因為有很多函數的實現調用了Tp的拷貝構造函數嗎?比如說上節提到的初始化函數:

any(_Tp&& __value) //調用_Tp copy ctor/move ctor
any(in_place_type_t<_Tp>, _Args&&... __args)  //調用_Tp parameterized ctor
any(in_place_type_t<_Tp>, initializer_list<_Up> __il, _Args&&... __args) //調用_Tp parameterized ctoroperator=(_Tp&& __rhs) //先構造臨時any對象(調用第一種情況),再move給*this

第一種case:如果__value是左值,則最終會調用到_Tp copy ctor:

_Manager_internal template<typename _Up>static void_S_create(_Storage& __storage, _Up&& __value){void* __addr = &__storage._M_buffer;::new (__addr) _Tp(std::forward<_Up>(__value));}_Manager_external template<typename _Up>static void_S_create(_Storage& __storage, _Up&& __value){__storage._M_ptr = new _Tp(std::forward<_Up>(__value));}

簡單寫個例子,證實我們的推斷:

  1 #include <any>2 #include <iostream>3 using namespace std;45 int main()6 {7     class Person{8         private:9             int _age;10             int _height;11         public:12             Person(){cout<<"default ctor"<<endl;}1314             Person(int age,int h):_age(age),_height(h){15                 cout<<"parameterized ctor"<<endl;16             }17             Person(const Person& o): _age(o._age), _height(o._height){ cout<<"copy ctor"<<endl; }1819             Person& operator=(const Person& o){20                 if (this != &o) {21                     _age = o._age;22                     _height = o._height;23                     cout<<"assignment"<<endl;24                 }25                 return *this;26             }2728             Person(Person&& o) noexcept : _age(std::move(o._age)), _height(std::move(o._height)) {29                 o._age = 0;30                 o._height = 0;31                 std::cout << "move ctor" << std::endl;32             }
3334             Person& operator=(Person&& o) noexcept {35                 if (this != &o) {36                     _age = std::move(o._age);37                     _height = std::move(o._height);38                     o._age = 0;39                     o._height = 0;40                     std::cout << "move assignment" << std::endl;41                 }42                 return *this;43             }4445             void print(){46                 cout<<"age:"<<_age<<" height:"<<_height<<endl;47             }48     };49     any a1{ Person(1,2) }; //call Person's move ctor50     any a2(a1);            //call Person's copy ctor51     cout<<"----------------"<<endl;5253     Person p = Person(1,2);54     any a3(p);             //call Person's copy ctor55     cout<<"----------------"<<endl;5657     any a4(std::in_place_type<Person>, 3, 4); //call Person's parameterized ctor58     Person& p4 = std::any_cast<Person&>(a4);  //ref, no copy of Person59     p4.print();6061     return 0;62 }

輸出如下:

parameterized ctor
move ctor
copy ctor
----------------
parameterized ctor
copy ctor
----------------
parameterized ctor
age:3 height:4
?

?50、54行都調用了Person's copy ctor.

50行:any copy

54行:由一個左值Person對象初始化一個any對象

但是不是所有暴露出來的接口都需要Tp支持copy constructible哪?是不是不支持就無法完成初始化+獲取回來數據 這種有意義的操作哪?顯然不是,請看57-59行。

57行:調用Tp的parameterized ctor構造了一個any對象,實際沒調用Tp的copy ctor, 但實現中依然要求Tp是copy constructible的, 如下所示:

    template <typename _Tp, typename... _Args, typename _VTp = decay_t<_Tp>,typename _Mgr = _Manager<_VTp>,__any_constructible_t<_VTp, _Args&&...> = false>explicitany(in_place_type_t<_Tp>, _Args&&... __args): _M_manager(&_Mgr::_S_manage){_Mgr::_S_create(_M_storage, std::forward<_Args>(__args)...);}template <typename _Res, typename _Tp, typename... _Args>using __any_constructible= enable_if<__and_<is_copy_constructible<_Tp>,is_constructible<_Tp, _Args...>>::value,_Res>;template <typename _Tp, typename... _Args>using __any_constructible_t= typename __any_constructible<bool, _Tp, _Args...>::type;

看到enable_if<__and_<is_copy_constructible<_Tp>沒?正是這廝!

不相信的話,我們做個試驗:把我們上面例子中的第17行改為copy ctor deleted. 刪除49~56行

Person(const Person& o)=delete;

編譯報錯!

?好了,我們修改一下any源代碼,把198行注釋掉以期盼甩掉對Tp copy ctor的限制:

196     template <typename _Tp, typename... _Args, typename _VTp = decay_t<_Tp>,
197               typename _Mgr = _Manager<_VTp>>
198               //__any_constructible_t<_VTp, _Args&&...> = false>
199       explicit
200       any(in_place_type_t<_Tp>, _Args&&... __args)
201       : _M_manager(&_Mgr::_S_manage)
202       {
203         _Mgr::_S_create(_M_storage, std::forward<_Args>(__args)...);
204       }

編譯竟然又報錯:

明明調用不到Tp的copy ctor啊, 為何報錯???

讓我們仔細看下589行:

573     any::_Manager_internal<_Tp>::
574     _S_manage(_Op __which, const any* __any, _Arg* __arg)
575     {
576       // The contained object is in _M_storage._M_buffer
577       auto __ptr = reinterpret_cast<const _Tp*>(&__any->_M_storage._M_buffer);
578       switch (__which)
579       {
580       case _Op_access:
581         __arg->_M_obj = const_cast<_Tp*>(__ptr);
582         break;
583       case _Op_get_type_info:
584 #if __cpp_rtti
585         __arg->_M_typeinfo = &typeid(_Tp);
586 #endif
587         break;
588       case _Op_clone:
589         ::new(&__arg->_M_any->_M_storage._M_buffer) _Tp(*__ptr);

?雖然運行時沒用到,但是編譯依然要編譯這一行,編譯::new ... Person(const Person&)肯定報錯啊,因為沒有這個函數!這下好了,不管你用到沒用到Tp的copy ctor, 為了編譯通過,你的Tp必須要有copy ctor了,躲不過了!

_Manager_external也一樣躲不過:

622       case _Op_clone:
623     __arg->_M_any->_M_storage._M_ptr = new _Tp(*__ptr);
624     __arg->_M_any->_M_manager = __any->_M_manager;

最后,不要忘了把any源代碼里的改動恢復回來。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/716582.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/716582.shtml
英文地址,請注明出處:http://en.pswp.cn/news/716582.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

動態SQL的處理

學習視頻&#xff1a;3001 動態SQL中的元素_嗶哩嗶哩_bilibili 目錄 1.1為什么學 1.2動態SQL中的元素 條件查詢操作 if 元素 choose、when、otherwise元素 where、trim元素 更新操作 set元素使用場景 復雜查詢操作 foreach 元素中的屬性 ?編輯 迭代數組 迭代List 迭代Map 1…

代碼隨想錄算法訓練營第二十七天|LeetCode93 復原IP地址、LeetCode78 子集、LeetCode90 子集II

93.復原IP地址 思路&#xff1a;要建立一個判斷子字符串是否合法的函數&#xff0c;判斷多種不合法的情況。在回溯函數中&#xff0c;參數除了s,和startindex還需要一個pointNum來記錄句點的數量&#xff0c;當句點的數量等于3時&#xff0c;判斷最后一個子串是否合法&#xf…

第3部分 原理篇2去中心化數字身份標識符(DID)(4)

3.2.3. DID解析 3.2.3.1. DID解析參與方 圖3-5 DID 解析過程 本聰老師&#xff1a;我們之前提到過&#xff0c;DID 解析過程是將 DID 轉換為對應的 DID 文檔。這樣做的目的是驗證 DID 所代表的主體的身份。那么解析過程會涉及哪些概念呢&#xff1f;我們看圖3-&#xff0c;DI…

端智能:面向手機計算環境的端云協同AI技術創新

近年來&#xff0c;隨著移動端設備軟硬件能力的進步&#xff0c;移動端的算力有了很大提升&#xff0c;同時面向移動端的機器學習框架和模型輕量化技術越來越成熟&#xff0c;端上的AI能力逐漸進入大眾視野&#xff0c;端智能在電商領域也開始逐步走向規模化應用。通過持續探索…

leetcode日記(35)跳躍游戲Ⅱ

想了一個晚上&#xff0c;第一個思路是用動態規劃&#xff0c;記錄走到每一個節點需要跳動的最小步數&#xff0c;大致方法是每走到一個節點就遍歷一下前面的全部節點&#xff0c;看看哪個節點可以一部跳到該節點&#xff0c;然后從中選取跳躍步數最小的節點&#xff0c;最后輸…

完美解決多個Echarts圖表自適應窗口、父容器寬高,并進行性能優化

場景 很多時候我們會在繪制echarts圖表時&#xff0c;使用以下方法監聽瀏覽器尺寸變化&#xff0c;讓圖表resize()完成自適應 window.addEventListener(resize, ()>{wordCloudChart.resize() })然后&#xff0c;這種自適應真的足夠周全嘛&#xff1f;有些時候&#xff0c;…

多元正態分布(Multivariate Normal Distribution)

多元正態分布&#xff08;Multivariate Normal Distribution&#xff09;&#xff0c;也稱為多變量高斯分布&#xff0c;是單變量正態分布&#xff08;高斯分布&#xff09;在多維空間中的推廣。它是描述位于多維空間中的隨機向量的分布情況的一種概率分布。多元正態分布在統計…

基于springboot+vue的城鎮保障性住房管理系統(前后端分離)

博主主頁&#xff1a;貓頭鷹源碼 博主簡介&#xff1a;Java領域優質創作者、CSDN博客專家、阿里云專家博主、公司架構師、全網粉絲5萬、專注Java技術領域和畢業設計項目實戰&#xff0c;歡迎高校老師\講師\同行交流合作 ?主要內容&#xff1a;畢業設計(Javaweb項目|小程序|Pyt…

練習 3 Web [ACTF2020 新生賽]Upload

[ACTF2020 新生賽]Upload1 中間有上傳文件的地方&#xff0c;試一下一句話木馬 txt 不讓傳txt 另存為tlyjpg&#xff0c;木馬文件上傳成功 給出了存放目錄&#xff1a; Upload Success! Look here~ ./uplo4d/06a9d80f64fded1e542a95e6d530c70a.jpg 下一步嘗試改木馬文件后綴…

云片 3.1(日常實習)面經

1、什么時候開始學習的前端 2、平常通過哪些方式學習 3、遇到bug怎么解決的 4、元素水平居中 5、display有哪些屬性 6、align-items除了center還有哪些屬性 7、display:none和visibility:hidden區別 8、常用的計量單位有哪些 9、rem和em是相對什么的 10、vw和vh有了解…

從頭構建gpt2 基于Transformer

從頭構建gpt2 基于Transformer VX關注{曉理紫|小李子}&#xff0c;獲取技術推送信息&#xff0c;如感興趣&#xff0c;請轉發給有需要的同學&#xff0c;謝謝支持&#xff01;&#xff01; 如果你感覺對你有所幫助&#xff0c;請關注我。 源碼獲取 VX關注曉理紫并回復“chatgpt…

CSS 自測題

盒模型的寬度計算 默認為標準盒模型 box-sizing:content-box; offsetWidth (內容寬度內邊距 邊框)&#xff0c;無外邊距 答案 122px通過 box-sizing: border-box; 可切換為 IE盒模型 offsetWidth width 即 100px margin 縱向重疊 相鄰元素的 margin-top 和 margin-bottom 會發…

leetcode-簡單

448. 找到所有數組中消失的數字 硬解 時間O(n)&#xff0c;空間O(n) class Solution { public:vector<int> findDisappearedNumbers(vector<int>& nums) {vector<int> result;vector<int> tem(nums.size()1, 0);for(int i: nums){tem[i] 1;}for…

Benchmark學習筆記

小記一篇Benchmark的學習筆記 1.什么是benchmark 在維基百科中&#xff0c;是這樣子講的 “As computer architecture advanced, it became more difficult to compare the performance of various computer systems simply by looking at their specifications.Therefore, te…

python標識符、變量和常量

一、保留字與標識符 1.1保留字 保留字是指python中被賦予特定意義的單詞&#xff0c;在開發程序時&#xff0c;不可以把這些保留字作為變量、函數、類、模塊和其它對象的名稱來使用。 比如&#xff1a;and、as、def、if、import、class、finally、with等 查詢這些關鍵字的方…

【LeetCode】升級打怪之路 Day 11 加餐:單調隊列

今日題目&#xff1a; 239. 滑動窗口最大值 | LeetCode 今天學習了單調隊列這種特殊的數據結構&#xff0c;思路很新穎&#xff0c;值得學習。 Problem&#xff1a;單調隊列 【必會】 與單調棧類似&#xff0c;單調隊列也是一種特殊的數據結構&#xff0c;它相比與普通的 que…

【NR 定位】3GPP NR Positioning 5G定位標準解讀(一)

目錄 前言 1. 3GPP規劃下的5G技術演進 2. 5G NR定位技術的發展 2.1 Rel-16首次對基于5G的定位技術進行標準化 2.2 Rel-17進一步提升5G定位技術的性能 3. Rel-18 關于5G定位技術的新方向、新進展 3.1 Sidelink高精度定位功能 3.2 針對上述不同用例&#xff0c;3GPP考慮按…

自動駕駛---Motion Planning之Speed Boundary(上)

1 背景 在上篇博客《自動駕駛---Motion Planning之Path Boundary》中,筆者主要介紹了path boundary的一些內容,通過將道路中感興趣區域的動靜態障礙物投影到車道坐標系中,用于確定L或者S的邊界,并利用道路信息再確定Speed的邊界,最后結合粗糙的速度曲線和路徑曲線,即可使…

Go-知識簡短變量聲明

Go-知識簡短變量聲明 1. 簡短變量聲明符2. 簡短變量賦值可能會重新聲明3. 簡短變量賦值不能用于函數外部4. 簡短變量賦值作用域問題5. 總結 githuio地址&#xff1a;https://a18792721831.github.io/ 1. 簡短變量聲明符 在Go語言中&#xff0c;可以使用關鍵字var或直接使用簡短…

【STK】手把手教你利用STK進行仿真-STK軟件基礎02 STK系統的軟件界面01 STK的界面窗口組成

STK系統是Windows窗口類型的桌面應用軟件,功能非常強大。在一個桌面應用軟件中集成了仿真對象管理、仿真對象屬性參數、設置、空間場景二三維可視化、場景顯示控制欲操作、仿真結果報表定制與分析、對象數據管理、仿真過程控制、外部接口連接和系統集成編程等復雜的功能。 STK…