खोज…
टिप्पणियों
कीवर्ड auto
एक टाइपनेम है जो स्वचालित रूप से कटौती प्रकार का प्रतिनिधित्व करता है।
यह C ++ 98 में पहले से ही एक आरक्षित कीवर्ड था, C से विरासत में मिला। C ++ के पुराने संस्करणों में, यह स्पष्ट रूप से बताया जा सकता है कि एक चर में स्वचालित भंडारण अवधि है:
int main()
{
auto int i = 5; // removing auto has no effect
}
वह पुराना अर्थ अब हटा दिया गया है।
मूल ऑटो नमूना
कीवर्ड auto
एक चर के प्रकार के ऑटो-कटौती प्रदान करता है।
यह लंबे प्रकार के नामों से निपटने के दौरान विशेष रूप से सुविधाजनक है:
std::map< std::string, std::shared_ptr< Widget > > table;
// C++98
std::map< std::string, std::shared_ptr< Widget > >::iterator i = table.find( "42" );
// C++11/14/17
auto j = table.find( "42" );
vector<int> v = {0, 1, 2, 3, 4, 5};
for(auto n: v)
std::cout << n << ' ';
लंबोदर के साथ:
auto f = [](){ std::cout << "lambda\n"; };
f();
प्रकार की पुनरावृत्ति से बचने के लिए:
auto w = std::make_shared< Widget >();
आश्चर्यजनक और अनावश्यक प्रतियों से बचने के लिए:
auto myMap = std::map<int,float>();
myMap.emplace(1,3.14);
std::pair<int,float> const& firstPair2 = *myMap.begin(); // copy!
auto const& firstPair = *myMap.begin(); // no copy!
प्रतिलिपि का कारण यह है कि लौटा हुआ प्रकार वास्तव में std::pair<const int,float>
!
ऑटो और अभिव्यक्ति टेम्पलेट्स
auto
भी समस्याएं पैदा कर सकता है जहां अभिव्यक्ति टेम्पलेट खेल में आते हैं:
auto mult(int c) {
return c * std::valarray<int>{1};
}
auto v = mult(3);
std::cout << v[0]; // some value that could be, but almost certainly is not, 3.
इसका कारण यह है कि valarray
पर operator*
आपको एक प्रॉक्सी ऑब्जेक्ट देता है जो valarray
को आलसी मूल्यांकन के साधन के रूप में संदर्भित करता है। auto
का उपयोग करके, आप एक झूलने वाला संदर्भ बना रहे हैं। mult
बजाय एक std::valarray<int>
वापस कर दिया था, तो कोड निश्चित रूप से 3 प्रिंट करेगा।
ऑटो, कास्ट, और संदर्भ
auto
कीवर्ड अपने आप में एक मान प्रकार का प्रतिनिधित्व करता है, जो int
या char
समान है। इसे क्रमशः एक कास्ट प्रकार या एक संदर्भ प्रकार का प्रतिनिधित्व करने के लिए const
कीवर्ड और &
सिंबल के साथ संशोधित किया जा सकता है। ये संशोधक संयुक्त हो सकते हैं।
इस उदाहरण में, s
एक मान प्रकार है (इसका प्रकार std::string
रूप में अनुमान लगाया जाएगा), इसलिए लूप के for
प्रत्येक पुनरावृत्ति वेक्टर से एक स्ट्रिंग को s
में कॉपी करता है।
std::vector<std::string> strings = { "stuff", "things", "misc" };
for(auto s : strings) {
std::cout << s << std::endl;
}
यदि लूप का शरीर s
को संशोधित करता है (जैसे कि s.append(" and stuff")
को कॉल s.append(" and stuff")
), तो केवल इस प्रति को संशोधित किया जाएगा, न कि strings
के मूल सदस्य को।
दूसरी ओर, यदि auto&
साथ s
घोषित किया गया है auto&
यह एक संदर्भ प्रकार होगा (अनुमान std::string&
), तो लूप के प्रत्येक पुनरावृत्ति पर इसे वेक्टर में एक स्ट्रिंग के संदर्भ में सौंपा जाएगा:
for(auto& s : strings) {
std::cout << s << std::endl;
}
इस लूप के शरीर में, के लिए संशोधन s
सीधे के तत्व को प्रभावित करेगा strings
कि यह संदर्भ।
अंत में, यदि s
को const auto&
घोषित किया जाता है, तो यह एक कॉन्स्ट रेफरेंस टाइप होगा, जिसका अर्थ है कि लूप के प्रत्येक पुनरावृत्ति पर इसे वेक्टर में एक स्ट्रिंग के लिए एक कॉन्स्ट रेफरेंस सौंपा जाएगा:
for(const auto& s : strings) {
std::cout << s << std::endl;
}
इस लूप के शरीर के भीतर, s
को संशोधित नहीं किया जा सकता है (अर्थात इस पर कोई गैर-कास्ट तरीके नहीं कहा जा सकता है)।
जब लूप्स के for
रेंज-आधारित के साथ auto
का उपयोग करते हैं, तो आमतौर पर const auto&
का उपयोग करना अच्छा होता है const auto&
अगर लूप बॉडी को लूप किए जाने वाले ढांचे को संशोधित नहीं किया जाएगा, क्योंकि यह अनावश्यक प्रतियों से बचा जाता है।
अनुगामी वापसी प्रकार
auto
का उपयोग सिंटैक्स में रिटर्न रिटर्न प्रकार के लिए किया जाता है:
auto main() -> int {}
के बराबर है
int main() {}
decltype
बजाय मापदंडों का उपयोग करने के लिए decltype
के साथ संयुक्त रूप से उपयोगी decltype
std::declval<T>
:
template <typename T1, typename T2>
auto Add(const T1& lhs, const T2& rhs) -> decltype(lhs + rhs) { return lhs + rhs; }
जेनेरिक लैम्ब्डा (C ++ 14)
C ++ 14 लैम्ब्डा तर्क में auto
का उपयोग करने की अनुमति देता है
auto print = [](const auto& arg) { std::cout << arg << std::endl; };
print(42);
print("hello world");
वह लंबोदर ज्यादातर बराबर है
struct lambda {
template <typename T>
auto operator ()(const T& arg) const {
std::cout << arg << std::endl;
}
};
और फिर
lambda print;
print(42);
print("hello world");
ऑटो और प्रॉक्सी ऑब्जेक्ट
कभी-कभी auto
काफी व्यवहार नहीं कर सकता जैसा कि एक प्रोग्रामर द्वारा अपेक्षित था। यह टाइप अभिव्यक्ति को घटाता है, तब भी जब टाइप कटौती सही काम नहीं है।
एक उदाहरण के रूप में, जब कोड में प्रॉक्सी ऑब्जेक्ट का उपयोग किया जाता है:
std::vector<bool> flags{true, true, false};
auto flag = flags[0];
flags.push_back(true);
यहाँ flag
bool
नहीं होगा, लेकिन std::vector<bool>::reference
, क्योंकि टेम्पलेट vector
के bool
विशेषज्ञता के लिए operator []
रूपांतरण ऑपरेटर operator bool
परिभाषित के साथ एक प्रॉक्सी वस्तु देता है।
जब flags.push_back(true)
कंटेनर को संशोधित करता है, तो यह छद्म संदर्भ एक तत्व का जिक्र करते हुए झूलने को समाप्त कर सकता है जो अब मौजूद नहीं है।
यह अगली स्थिति को भी संभव बनाता है:
void foo(bool b);
std::vector<bool> getFlags();
auto flag = getFlags()[5];
foo(flag);
vector
को तुरंत खारिज कर दिया vector
है, इसलिए flag
एक तत्व के लिए एक छद्म संदर्भ है जिसे त्याग दिया गया है। foo
को कॉल अपरिभाषित व्यवहार को आमंत्रित करता है।
इस तरह के मामलों में आप auto
साथ एक वैरिएबल की घोषणा कर सकते हैं और इसे उस प्रकार के कास्टिंग के द्वारा आरंभ कर सकते हैं जिसे आप कम करना चाहते हैं:
auto flag = static_cast<bool>(getFlags()[5]);
लेकिन उस बिंदु पर, बस bool
साथ auto
जगह अधिक समझ में आता है।
एक अन्य मामला जहां प्रॉक्सी ऑब्जेक्ट समस्या पैदा कर सकता है वह है अभिव्यक्ति टेम्पलेट । उस स्थिति में, टेम्प्लेट कभी-कभी दक्षता पूर्णता के लिए वर्तमान पूर्ण-अभिव्यक्ति से परे रहने के लिए डिज़ाइन नहीं किए जाते हैं और प्रॉक्सी ऑब्जेक्ट का उपयोग अपरिभाषित व्यवहार के कारण होता है।