C++
std :: संस्करण
खोज…
टिप्पणियों
वेरिएंट कच्चे union
उपयोग के लिए एक प्रतिस्थापन है। यह प्रकार-सुरक्षित है और जानता है कि यह किस प्रकार का है, और यह ध्यान से वस्तुओं का निर्माण और विनाश करता है जब यह होना चाहिए।
यह लगभग कभी खाली नहीं होता है: केवल कोने के मामलों में जहां इसकी सामग्री फेंकता है और यह सुरक्षित रूप से वापस नहीं हो सकता है यह खाली स्थिति में समाप्त होता है।
यह कुछ हद तक एक std::tuple
तरह व्यवहार करता है, और कुछ std::optional
।
std::get
और std::get_if
का उपयोग करना आमतौर पर एक बुरा विचार है। सही उत्तर आमतौर पर std::visit
, जो आपको हर संभावना से निपटने का मौका देता है। if constexpr
का उपयोग visit
भीतर किया जा सकता है, यदि आपको अपने व्यवहार को शाखा देने की आवश्यकता है, बजाय रनटाइम चेक के एक अनुक्रम करने के लिए जो नकल करता है कि visit
अधिक कुशलता से क्या करेगी।
मूल std :: भिन्न उपयोग
यह एक वैरिएंट (एक टैग की गई यूनियन) बनाता है जो int
या string
को स्टोर कर सकता है।
std::variant< int, std::string > var;
हम इसमें से किसी एक प्रकार को स्टोर कर सकते हैं:
var = "hello"s;
और हम std::visit
माध्यम से सामग्री का उपयोग कर सकते हैं std::visit
:
// Prints "hello\n":
visit( [](auto&& e) {
std::cout << e << '\n';
}, var );
एक बहुरूपी लैम्ब्डा या इसी तरह के फ़ंक्शन ऑब्जेक्ट में गुजरने से।
यदि हम निश्चित हैं तो हमें पता है कि यह किस प्रकार का है, हम इसे प्राप्त कर सकते हैं:
auto str = std::get<std::string>(var);
लेकिन अगर यह गलत हुआ तो हम इसे फेंक देंगे। get_if
:
auto* str = std::get_if<std::string>(&var);
यदि आप गलत अनुमान nullptr
तो nullptr
देता है।
वेरिएंट कोई डायनेमिक मेमोरी आवंटन (उनके निहित प्रकारों से आवंटित किया गया है) की गारंटी देता है। एक प्रकार के केवल एक प्रकार को वहां संग्रहीत किया जाता है, और दुर्लभ मामलों में (असाइनमेंट करते समय अपवादों को शामिल करने और वापस बाहर निकलने का कोई सुरक्षित तरीका नहीं है) संस्करण खाली हो सकता है।
वेरिएंट आपको एक चर में कई मूल्य प्रकारों को सुरक्षित और कुशलता से संग्रहीत करने देता है। वे मूल रूप से स्मार्ट हैं, टाइप-सेफ union
एस।
छद्म विधि संकेत बनाएँ
यह एक उन्नत उदाहरण है।
आप हल्के वजन प्रकार के क्षरण के लिए संस्करण का उपयोग कर सकते हैं।
template<class F>
struct pseudo_method {
F f;
// enable C++17 class type deduction:
pseudo_method( F&& fin ):f(std::move(fin)) {}
// Koenig lookup operator->*, as this is a pseudo-method it is appropriate:
template<class Variant> // maybe add SFINAE test that LHS is actually a variant.
friend decltype(auto) operator->*( Variant&& var, pseudo_method const& method ) {
// var->*method returns a lambda that perfect forwards a function call,
// behaving like a method pointer basically:
return [&](auto&&...args)->decltype(auto) {
// use visit to get the type of the variant:
return std::visit(
[&](auto&& self)->decltype(auto) {
// decltype(x)(x) is perfect forwarding in a lambda:
return method.f( decltype(self)(self), decltype(args)(args)... );
},
std::forward<Var>(var)
);
};
}
};
यह एक प्रकार बनाता है जो operator->*
ओवरलोड operator->*
बाएं हाथ पर एक Variant
साथ।
// C++17 class type deduction to find template argument of `print` here.
// a pseudo-method lambda should take `self` as its first argument, then
// the rest of the arguments afterwards, and invoke the action:
pseudo_method print = [](auto&& self, auto&&...args)->decltype(auto) {
return decltype(self)(self).print( decltype(args)(args)... );
};
अब अगर हमारे पास print
विधि के साथ 2 प्रकार हैं:
struct A {
void print( std::ostream& os ) const {
os << "A";
}
};
struct B {
void print( std::ostream& os ) const {
os << "B";
}
};
ध्यान दें कि वे असंबंधित प्रकार हैं। हम कर सकते हैं:
std::variant<A,B> var = A{};
(var->*print)(std::cout);
और यह कॉल को सीधे हमारे लिए A::print(std::cout)
भेज देगा। यदि हमने इसके बजाय B{}
साथ var
को इनिशियलाइज़ किया है, तो यह B::print(std::cout)
लिए प्रेषण करेगा।
यदि हमने एक नया प्रकार C बनाया है:
struct C {};
फिर:
std::variant<A,B,C> var = A{};
(var->*print)(std::cout);
संकलित करने में विफल रहेगा, क्योंकि कोई C.print(std::cout)
विधि नहीं है।
उपरोक्त का विस्तार करने से नि: शुल्क फ़ंक्शन print
एस का पता लगाया जा सकता है और इसका उपयोग किया जा सकता है, संभवत: if constexpr
print
छद्म पद्धति के भीतर if constexpr
का उपयोग किया जाता है।
लाइव उदाहरण वर्तमान में boost::variant
std::variant
स्थान पर std::variant
।
एक `एसटीडी :: संस्करण` का निर्माण
यह आवंटनकर्ताओं को कवर नहीं करता है।
struct A {};
struct B { B()=default; B(B const&)=default; B(int){}; };
struct C { C()=delete; C(int) {}; C(C const&)=default; };
struct D { D( std::initializer_list<int> ) {}; D(D const&)=default; D()=default; };
std::variant<A,B> var_ab0; // contains a A()
std::variant<A,B> var_ab1 = 7; // contains a B(7)
std::variant<A,B> var_ab2 = var_ab1; // contains a B(7)
std::variant<A,B,C> var_abc0{ std::in_place_type<C>, 7 }; // contains a C(7)
std::variant<C> var_c0; // illegal, no default ctor for C
std::variant<A,D> var_ad0( std::in_place_type<D>, {1,3,3,4} ); // contains D{1,3,3,4}
std::variant<A,D> var_ad1( std::in_place_index<0> ); // contains A{}
std::variant<A,D> var_ad2( std::in_place_index<1>, {1,3,3,4} ); // contains D{1,3,3,4}