您好,登錄后才能下訂單哦!
這篇文章主要介紹了C++的std::any怎么使用的相關(guān)知識(shí),內(nèi)容詳細(xì)易懂,操作簡(jiǎn)單快捷,具有一定借鑒價(jià)值,相信大家閱讀完這篇C++的std::any怎么使用文章都會(huì)有所收獲,下面我們一起來(lái)看看吧。
一般來(lái)說(shuō),c++是一種具有類(lèi)型綁定和類(lèi)型安全性的語(yǔ)言。值對(duì)象聲明為具有特定類(lèi)型,該類(lèi)型定義哪些操作是可能的以及它們的行為方式。值對(duì)象不能改變它們的類(lèi)型。
std: any是一種值類(lèi)型,它能夠更改其類(lèi)型,同時(shí)仍然具有類(lèi)型安全性。也就是說(shuō),對(duì)象可以保存任意類(lèi)型的值,但是它們知道當(dāng)前保存的值是哪種類(lèi)型。在聲明此類(lèi)型的對(duì)象時(shí),不需要指定可能的類(lèi)型。
訣竅在于,對(duì)象同時(shí)擁有包含的值和使用typeid包含值的類(lèi)型。因?yàn)檫@個(gè)值可以有任何大小,所以可以在堆上分配內(nèi)存,鼓勵(lì)實(shí)現(xiàn)避免小對(duì)象的動(dòng)態(tài)分配。也就是說(shuō),如果分配一個(gè)字符串,對(duì)象將為該值分配內(nèi)存并復(fù)制該字符串,同時(shí)也在內(nèi)部存儲(chǔ)分配的字符串。稍后,可以執(zhí)行運(yùn)行時(shí)檢查來(lái)確定當(dāng)前值的類(lèi)型,并使用any_cast<該值的類(lèi)型>獲取值。
下面的例子演示了std::any:
std::any a; // a is empty std::any b = 4.3; // b has value 4.3 of type double a = 42; // a has value 42 of type int b = std::string{"hi"}; // b has value "hi" of type std::string if (a.type() == typeid(std::string)) { std::string s = std::any_cast<std::string>(a); useString(s); } else if (a.type() == typeid(int)) { useInt(std::any_cast<int>(a)); }
可以聲明std::any為空或由特定類(lèi)型的值初始化。初始值的類(lèi)型成為所包含值的類(lèi)型。通過(guò)使用成員函數(shù)type(),可以根據(jù)任何類(lèi)型的類(lèi)型ID檢查所包含值的類(lèi)型。如果對(duì)象是空的,對(duì)象類(lèi)型ID是typeid(void)。要訪問(wèn)包含的值,可以通過(guò)std::any_cast<對(duì)象類(lèi)型>的方式:
auto s = std::any_cast<std::string>(a);
如果轉(zhuǎn)換失敗,因?yàn)閷?duì)象為空或包含的類(lèi)型不匹配,則拋出std::bad_any_cast。因此,在不檢查或不知道類(lèi)型的情況下,最好實(shí)現(xiàn)以下功能:
try { auto s = std::any_cast<std::string>(a); ... } catch (std::bad_any_cast& e) { std::cerr << "EXCEPTION: " << e.what() << '\n'; }
注意,std::any_cast<>創(chuàng)建了一個(gè)傳遞類(lèi)型的對(duì)象。如果將std::string作為模板參數(shù)傳遞給std::any_cast<>,它將創(chuàng)建一個(gè)臨時(shí)string(一個(gè)prvalue),然后用它初始化新對(duì)象s。如果沒(méi)有這樣的初始化,通常最好轉(zhuǎn)換為引用類(lèi)型,以避免創(chuàng)建臨時(shí)對(duì)象:
std::cout << std::any_cast<const std::string&>(a);
要修改該值,需要轉(zhuǎn)換為對(duì)應(yīng)的引用類(lèi)型:
std::any_cast<std::string&>(a) = "world";
還可以為std::any對(duì)象的地址調(diào)用std::any_cast。在這種情況下,如果類(lèi)型匹配,則強(qiáng)制轉(zhuǎn)換返回相應(yīng)的地址指針;如果不匹配,則返回nullptr:
auto p = std::any_cast<std::string>(&a); if (p) { ... }
例1:
#include <iostream> #include <any> int main() { std::any i = 42; const auto ptr = std::any_cast<int>(&i); if (ptr) { std::cout << ptr << std::endl; } return 0; }
結(jié)果如下:
要清空現(xiàn)有std::任何可以調(diào)用的對(duì)象:
方法1:a.reset(); // makes it empty
方法2:a = std::any{};
方法3: a = {};
可以直接檢查對(duì)象是否為空:
if (a.has_value()) { ... }
還要注意,值是使用衰減類(lèi)型存儲(chǔ)的(數(shù)組轉(zhuǎn)換為指針,忽略頂層引用和const)。對(duì)于字符串常量,這意味著值類(lèi)型是const char*。要檢查type()并使用std::any_cast<>,必須使用以下類(lèi)型:
std::any a = "hello"; // type() is const char* if (a.type() == typeid(const char*)) { // true ... } if (a.type() == typeid(std::string)) { // false ... } std::cout << std::any_cast<const char*>(v[1]) << '\n'; // OK std::cout << std::any_cast<std::string>(v[1]) << '\n'; // EXCEPTION
std::any沒(méi)有定義比較運(yùn)算符(因此,不能比較或排序?qū)ο?,沒(méi)有定義hash函數(shù),也沒(méi)有定義value()成員函數(shù)。由于類(lèi)型只在運(yùn)行時(shí)才知道,所以不能使用泛型lambdas處理與類(lèi)型無(wú)關(guān)的當(dāng)前值??偸切枰\(yùn)行時(shí)函數(shù)std::any_cast<>來(lái)處理當(dāng)前值。
然而,可以將std::任何對(duì)象放入容器中。
例2:
#include <iostream> #include <vector> #include <any> int main() { std::vector<std::any> v; v.push_back(42); std::string s = "hello"; v.push_back(s); for (const auto& a : v) { if (a.type() == typeid(std::string)) { std::cout << "string: " << std::any_cast<const std::string&>(a) << '\n'; } else if (a.type() == typeid(int)) { std::cout << "int: " << std::any_cast<int>(a) << '\n'; } } }
結(jié)果如下:
本節(jié)詳細(xì)描述std::any的類(lèi)型和操作。
在頭文件<any>中,c++標(biāo)準(zhǔn)庫(kù)定義了類(lèi)std::any,如下所示:
namespace std { class any; }
也就是說(shuō),std::any根本不是類(lèi)模板。
此外,定義了以下類(lèi)型和對(duì)象:
如果類(lèi)型轉(zhuǎn)換失敗,則拋出異常類(lèi)型std::bad_any_cast,它派生自std::bad_cast,而std::bad_cast派生自std::exception。
any對(duì)象還可以使用<utility>中定義的對(duì)象std::in_place_type(類(lèi)型為std::in_place_type_t)。
std::any操作
函數(shù) | 說(shuō)明 |
constructors | 創(chuàng)建一個(gè)any對(duì)象(可能調(diào)用底層類(lèi)型的構(gòu)造函數(shù)) |
make_any() | 創(chuàng)建一個(gè)any對(duì)象(傳遞值來(lái)初始化它) |
destructor | 銷(xiāo)毀any對(duì)象 |
= | 分配一個(gè)新值 |
emplace<T>() | 分配一個(gè)類(lèi)型為T(mén)的新值 |
reset() | 銷(xiāo)毀any對(duì)象的值(使對(duì)象為空) |
has_value() | 返回對(duì)象是否具有值 |
type() | 返回當(dāng)前類(lèi)型為std::type_info對(duì)象 |
any_cast<T>() | 使用當(dāng)前值作為類(lèi)型T的值(如果其他類(lèi)型除外) |
swap() | 交換兩個(gè)any對(duì)象的值 |
1. 構(gòu)造函數(shù)
默認(rèn)情況下,std::any的初始值為空。
std::any a1; // a1 is empty
如果傳遞一個(gè)值進(jìn)行初始化,則將其衰減類(lèi)型用作所包含值的類(lèi)型:
std::any a2 = 42; // a2 contains value of type int std::any a3 = "hello"; // a2 contains value of type const char*
要保存與初始值類(lèi)型不同的類(lèi)型,必須使用in_place_type標(biāo)記:
std::any a4{std::in_place_type<long>, 42}; std::any a5{std::in_place_type<std::string>, "hello"};
即使傳遞給in_place_type的類(lèi)型也會(huì)衰減。下面的聲明包含一個(gè)const char*:
std::any a5b{std::in_place_type<const char[6]>, "hello"};
要通過(guò)多個(gè)參數(shù)初始化可選對(duì)象,必須創(chuàng)建該對(duì)象或?qū)td::in_place_type添加為第一個(gè)參數(shù)(不能推斷包含的類(lèi)型):
std::any a6{std::complex{3.0, 4.0}}; std::any a7{std::in_place_type<std::complex<double>>, 3.0, 4.0};
甚至可以傳遞一個(gè)初始化器列表,后面跟著附加的參數(shù):
// initialize a std::any with a set with lambda as sorting criterion: auto sc = [] (int x, int y) { return std::abs(x) < std::abs(y);}; std::any a8{std::in_place_type<std::set<int,decltype(sc)>>, {4, 8, -7, -2, 0, 5}, sc};
注意,還有一個(gè)方便的函數(shù)make_any<>(),它可以用于單個(gè)或多個(gè)參數(shù)(不需要in_place_type參數(shù))。必須顯式指定初始化的類(lèi)型(如果只傳遞一個(gè)參數(shù),則不會(huì)推導(dǎo)出初始化的類(lèi)型):
auto a10 = std::make_any<float>(3.0); auto a11 = std::make_any<std::string>("hello"); auto a13 = std::make_any<std::complex<double>>(3.0, 4.0); auto a14 = std::make_any<std::set<int,decltype(sc)>>({4, 8, -7, -2, 0, 5}, sc);
2. 訪問(wèn)值
要訪問(wèn)包含的值,必須使用std::any_cast<>將其轉(zhuǎn)換為其類(lèi)型。將該值轉(zhuǎn)換為一個(gè)字符串,有幾個(gè)選項(xiàng):
std::any_cast<std::string>(a) // yield copy of the value std::any_cast<std::string&>(a); // write value by reference std::any_cast<const std::string&>(a); // read-access by reference
在這里,如果轉(zhuǎn)換失敗,將拋出std::bad_any_cast異常。
如果把std::any中所包含的類(lèi)型轉(zhuǎn)換為移除了傳遞類(lèi)型的頂層引用后的類(lèi)型ID,則轉(zhuǎn)換類(lèi)型是適合的。如下:
#include <iostream> #include <string> #include <any> int main() { const auto& s = std::make_any<std::string>("hello"); if (s.type() == typeid(std::string))//刪除頂層cosnt和引用后的類(lèi)型 { auto a = std::any_cast<std::string>(s); std::cout << a << std::endl; } return 0; }
結(jié)果如下:
如果類(lèi)型不匹配轉(zhuǎn)換失敗了,傳遞一個(gè)地址將會(huì)返回nullptr:
auto a = std::make_any<std::string>("hello"); std::any_cast<std::string>(&a) // write-access via pointer std::any_cast<const std::string>(&a); // read-access via pointer
注意,這里轉(zhuǎn)換到引用會(huì)導(dǎo)致運(yùn)行時(shí)錯(cuò)誤:
std::any_cast<std::string&>(&a); // RUN-TIME ERROR
3. 修改值
相應(yīng)的賦值和emplace()操作。例如:
#include <iostream> #include <string> #include <any> #include <complex> int main() { std::any a; a = 42; // a contains value of type int a = "hello"; // a contains value of type const char* a.emplace<std::string>("hello world");// a contains value of type std::string return 0; }
結(jié)果如下:
4. 移動(dòng)語(yǔ)法
std: any也支持移動(dòng)語(yǔ)義。但是,請(qǐng)注意,move語(yǔ)義必須滿足包含的類(lèi)型具有可復(fù)制構(gòu)造函數(shù)。也就是說(shuō),不支持只移動(dòng)類(lèi)型作為包含值類(lèi)型。處理move語(yǔ)義的最佳方法可能并不明顯。所以,你應(yīng)該這樣做:
std::string s("hello, world!"); std::any a; a = std::move(s); // move s into a s = std::move(std::any_cast<string&>(a)); // move assign string in a to s
與通常的從對(duì)象移動(dòng)的情況一樣,在最后一次調(diào)用之后,所包含的值a是未指定的。因此,可以使用a作為字符串,只要沒(méi)有對(duì)所包含的字符串值的值做任何假設(shè)。
注意:
s = std::any_cast<string>(std::move(a));
也可以,但需要一個(gè)額外的移動(dòng)。然而,以下內(nèi)容是危險(xiǎn)的(盡管它是c++標(biāo)準(zhǔn)中的一個(gè)例子):
std::any_cast<string&>(a) = std::move(s2); // OOPS: a to hold a string
只有當(dāng)包含的值已經(jīng)是字符串時(shí),才可以這樣做。如果沒(méi)有,轉(zhuǎn)換將拋出一個(gè)std::bad_any_cast異常。
關(guān)于“C++的std::any怎么使用”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對(duì)“C++的std::any怎么使用”知識(shí)都有一定的了解,大家如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。