कोई सी ++ प्यार नहीं करता है जब यह प्रश्नों की "छिपी हुई विशेषताएं" की बात आती है? लगा कि मैं इसे वहीं फेंक दूंगा। C ++ की कुछ छिपी हुई विशेषताएँ क्या हैं?
कोई सी ++ प्यार नहीं करता है जब यह प्रश्नों की "छिपी हुई विशेषताएं" की बात आती है? लगा कि मैं इसे वहीं फेंक दूंगा। C ++ की कुछ छिपी हुई विशेषताएँ क्या हैं?
जवाबों:
अधिकांश C ++ प्रोग्रामर टर्नरी ऑपरेटर से परिचित हैं:
x = (y < 0) ? 10 : 20;
हालांकि, उन्हें इस बात का एहसास नहीं है कि इसका इस्तेमाल एक लवलीन के रूप में किया जा सकता है:
(a == 0 ? a : b) = 1;
जिसके लिए आशुलिपि है
if (a == 0)
a = 1;
else
b = 1;
सावधानी से प्रयोग करें :-)
(value ? function1 : function2)()
:।
function1
और function2
फ़ंक्शन बिंदुओं में परिवर्तित कर दिया जाता है, और परिणाम को वापस बदल दिया जाता है।
आप URI को बिना त्रुटि के C ++ स्रोत में डाल सकते हैं। उदाहरण के लिए:
void foo() {
http://stackoverflow.com/
int bar = 4;
...
}
goto
, जो C ++ के पास है)। दो स्लैश के बाद कुछ भी एक टिप्पणी है। इसलिए, के साथ http://stackoverflow.com
, http
एक लेबल है (आप सैद्धांतिक रूप से लिख सकते हैं goto http;
), और //stackoverflow.com
बस एक अंत-पंक्ति टिप्पणी है। ये दोनों कानूनी C ++ हैं, इसलिए निर्माण संकलित करता है। यह निश्चित रूप से उपयोगी कुछ भी नहीं करता है।
goto http;
वास्तव में URL का अनुसरण नहीं करता है। :(
सूचक अंकगणित।
C ++ प्रोग्रामर उन बग्स से बचने के लिए पसंद करते हैं, जो बग को पेश किए जा सकते हैं।
सबसे अच्छा C ++ मैंने कभी देखा है? एनालॉग शाब्दिक।
मैं वहां के अधिकांश पदों से सहमत हूं: C ++ एक बहु-प्रतिमान भाषा है, इसलिए "छिपी हुई" विशेषताएँ जो आपको मिलेंगी ("अपरिभाषित व्यवहारों के अलावा" जो आपको हर कीमत पर बचनी चाहिए) सुविधाओं के चतुर उपयोग हैं।
उन सुविधाओं में से अधिकांश भाषा की सुविधाओं में निर्मित नहीं हैं, लेकिन पुस्तकालय आधारित हैं।
सबसे महत्वपूर्ण RAII है , जिसे अक्सर C ++ डेवलपर्स द्वारा सी दुनिया से आने वाले वर्षों के लिए अनदेखा किया जाता है। ऑपरेटर ओवरलोडिंग अक्सर एक गलतफहमी की विशेषता होती है जो सरणी-जैसे व्यवहार (सबस्क्रिप्ट ऑपरेटर), सूचक जैसे संचालन (स्मार्ट पॉइंटर्स) और बिल्ड-इन-समान संचालन (मैट्रिसेस को गुणा करना) को सक्षम करता है।
अपवाद का उपयोग अक्सर मुश्किल होता है, लेकिन कुछ काम के साथ, अपवाद सुरक्षा के माध्यम से वास्तव में मजबूत कोड का उत्पादन कर सकते हैं विशिष्टताओं (कोड सहित, जो विफल नहीं होगा, या जिसमें एक कमिट जैसी विशेषताएं होंगी जो सफल होंगी, या वापस वापस आ जाएगी। इसकी मूल स्थिति)।
C ++ की "छिपी" सुविधा का सबसे प्रसिद्ध टेम्पलेट मेटाप्रोग्रामिंग है , क्योंकि यह आपको रनटाइम के बजाय अपने प्रोग्राम को आंशिक रूप से (या पूरी तरह से) निष्पादित करने में सक्षम बनाता है। यह मुश्किल है, हालांकि, और आपको इसे आज़माने से पहले टेम्प्लेट पर एक ठोस समझ होनी चाहिए।
अन्य C ++ के पूर्वज, यानी C के बाहर "प्रोग्रामिंग के तरीके" के निर्माण के लिए कई प्रतिमानों का उपयोग करते हैं।
फंक्शनलर्स का उपयोग करके , आप अतिरिक्त प्रकार की सुरक्षा और स्टेटफुल होने के साथ फंक्शन्स का अनुकरण कर सकते हैं। कमांड पैटर्न का उपयोग करके , आप कोड निष्पादन में देरी कर सकते हैं। कई अन्य डिज़ाइन पैटर्न को आसानी से और कुशलता से C ++ में लागू किया जा सकता है ताकि वैकल्पिक कोडिंग शैलियों का उत्पादन किया जा सके, जो "आधिकारिक C ++ प्रतिमान" की सूची के अंदर न हों।
टेम्प्लेट का उपयोग करके , आप उस कोड का उत्पादन कर सकते हैं जो कि सबसे प्रकार पर काम करेगा, जिसमें वह नहीं है जिसे आपने पहले सोचा था। आप टाइप सुरक्षा बढ़ा सकते हैं, भी (जैसे एक स्वचालित टाइपसेक मॉलोक / रियललोक / फ्री)। C ++ ऑब्जेक्ट विशेषताएँ वास्तव में शक्तिशाली हैं (और इस प्रकार, खतरनाक अगर लापरवाही से उपयोग की जाती है), लेकिन यहां तक कि गतिशील बहुरूपता का C ++ में इसका स्थिर संस्करण है: CRTP ।
मैंने पाया है कि स्कॉट मेयर्स की अधिकांश " प्रभावी C ++ " -प्रस्तुत पुस्तकें या " हर्ब सटर की असाधारण C ++ " -प्रकार की पुस्तकें दोनों को पढ़ना आसान है, और C ++ की ज्ञात और कम ज्ञात विशेषताओं पर जानकारी का काफी खजाना है।
मेरी पसंद में से एक है जो किसी भी जावा प्रोग्रामर के बालों को हॉरर से उभारना चाहिए: सी ++ में, एक ऑब्जेक्ट में एक फीचर जोड़ने का सबसे ऑब्जेक्ट-ओरिएंटेड तरीका एक सदस्य के बजाय गैर-सदस्य गैर-मित्र फ़ंक्शन के माध्यम से है। फ़ंक्शन (अर्थात कक्षा विधि), क्योंकि:
C ++ में, एक वर्ग का इंटरफ़ेस इसके सदस्य-फ़ंक्शन और समान नामस्थान में गैर-सदस्य फ़ंक्शन दोनों है
गैर-मित्र गैर-सदस्य कार्यों का वर्ग आंतरिक तक कोई विशेषाधिकार प्राप्त नहीं है। जैसे, एक गैर-सदस्य गैर-दोस्त से अधिक सदस्य फ़ंक्शन का उपयोग करने से कक्षा का इनकैप्सुलेशन कमजोर हो जाएगा।
यह कभी भी अनुभवी डेवलपर्स को आश्चर्यचकित करने में विफल नहीं होता है।
(स्रोत: दूसरों के बीच, हर्ब सटर के ऑनलाइन गुरु # द वीक # 84: http://www.gotw.ca/gotw/084.htm )
एक भाषा सुविधा जिसे मैं कुछ हद तक छिपा हुआ मानता हूं, क्योंकि मैंने स्कूल में अपने पूरे समय के बारे में कभी नहीं सुना था, नाम है उपनाम। यह मेरे ध्यान में नहीं लाया गया जब तक कि मैं इसके उदाहरणों को बढ़ावा देने के दस्तावेज में नहीं चला। बेशक, अब जब मुझे इसके बारे में पता है तो आप इसे किसी भी मानक C ++ संदर्भ में पा सकते हैं।
namespace fs = boost::filesystem;
fs::path myPath( strPath, fs::native );
using
।
न केवल एक for
लूप के इनिट भाग में चर घोषित किए जा सकते हैं , बल्कि कक्षाएं और फ़ंक्शन भी।
for(struct { int a; float b; } loop = { 1, 2 }; ...; ...) {
...
}
यह विभिन्न प्रकारों के कई चर के लिए अनुमति देता है।
सरणी ऑपरेटर सहयोगी है।
A [8] * (A + 8) का पर्याय है। चूंकि जोड़ सहयोगी है, इसलिए इसे * (8 + ए) के रूप में फिर से लिखा जा सकता है, जो ..... 8 [ए] का पर्याय है।
आपने उपयोगी नहीं कहा ... :-)
A
कोई फर्क नहीं पड़ता। उदाहरण के लिए, यदि A
कोई होता char*
, तो कोड अभी भी मान्य होता।
एक बात जो बहुत कम जानी जाती है वह यह है कि यूनियनें भी टेम्प्लेट हो सकती हैं:
template<typename From, typename To>
union union_cast {
From from;
To to;
union_cast(From from)
:from(from) { }
To getTo() const { return to; }
};
और उनके पास निर्माता और सदस्य कार्य भी हो सकते हैं। बस कुछ भी नहीं है कि विरासत (आभासी कार्यों सहित) के साथ क्या करना है।
From
और To
स्थापित करने और उपयोग किया जाता है तदनुसार। इस तरह के संघ को परिभाषित व्यवहार के साथ इस्तेमाल किया जा सकता है (हालांकि To
अहस्ताक्षरित चार की एक सरणी या एक प्रारंभिक अनुक्रम साझा करने के साथ From
)। यहां तक कि अगर आप इसे अपरिभाषित तरीके से उपयोग करते हैं, तो भी यह निम्न-स्तर के काम के लिए उपयोगी हो सकता है। वैसे भी, यह संघ के खाके का सिर्फ एक उदाहरण है - टेम्पर्ड यूनियन के लिए अन्य उपयोग हो सकते हैं।
C ++ एक मानक है, इसमें कोई छिपी हुई विशेषताएं नहीं होनी चाहिए ...
C ++ एक बहु-प्रतिमान भाषा है, आप अपने पिछले पैसे को छिपे हुए फीचर्स पर दांव लगा सकते हैं। कई में से एक उदाहरण: टेम्पलेट मेटाप्रोग्रामिंग । मानकों की समिति में किसी का भी इरादा ट्यूरिंग-पूर्ण उप-भाषा होने का नहीं है जिसे संकलन-समय पर निष्पादित किया जाता है।
एक अन्य छिपी हुई विशेषता जो C में काम नहीं करती है, वह है यूनिटी की कार्यक्षमता +
ऑपरेटर । आप इसे सभी प्रकार की चीजों को बढ़ावा देने और क्षय करने के लिए उपयोग कर सकते हैं
+AnEnumeratorValue
और आपके एन्यूमरेटर मूल्य जो पहले अपने एन्यूमरेशन प्रकार का था, अब पूर्ण पूर्णांक प्रकार है जो इसके मूल्य को फिट कर सकता है। मैन्युअल रूप से, आप शायद ही उस प्रकार को जानते होंगे! उदाहरण के लिए यह आवश्यक है जब आप अपनी गणना के लिए एक अतिभारित ऑपरेटर को लागू करना चाहते हैं।
आपको एक वर्ग का उपयोग करना होगा जो वर्ग परिभाषा से बाहर एक इन-क्लास स्थिर इनिलाइज़र का उपयोग करता है, लेकिन कभी-कभी यह लिंक करने में विफल रहता है? ऑपरेटर अपने प्रकारों पर निर्भरता या निर्भरता बनाए बिना एक अस्थायी बनाने में मदद कर सकता है
struct Foo {
static int const value = 42;
};
// This does something interesting...
template<typename T>
void f(T const&);
int main() {
// fails to link - tries to get the address of "Foo::value"!
f(Foo::value);
// works - pass a temporary value
f(+Foo::value);
}
क्या आप एक फंक्शन में दो पॉइंटर्स पास करना चाहते हैं, लेकिन यह सिर्फ काम नहीं करेगा? ऑपरेटर मदद कर सकता है
// This does something interesting...
template<typename T>
void f(T const& a, T const& b);
int main() {
int a[2];
int b[3];
f(a, b); // won't work! different values for "T"!
f(+a, +b); // works! T is "int*" both time
}
कांस्टेबल संदर्भों से बंधे अस्थायी लोगों का जीवनकाल वह होता है जिसके बारे में बहुत कम लोग जानते हैं। या कम से कम यह C ++ ज्ञान का मेरा पसंदीदा टुकड़ा है जिसके बारे में ज्यादातर लोग नहीं जानते हैं।
const MyClass& x = MyClass(); // temporary exists as long as x is in scope
एक अच्छी सुविधा जिसका उपयोग अक्सर नहीं किया जाता है वह है कार्य-व्यापी प्रयास-कैच ब्लॉक:
int Function()
try
{
// do something here
return 42;
}
catch(...)
{
return -1;
}
मुख्य उपयोग अन्य अपवाद वर्ग और पुनर्खरीद के लिए अपवाद का अनुवाद करना होगा, या अपवादों और रिटर्न-आधारित त्रुटि कोड हैंडलिंग के बीच अनुवाद करना होगा।
return
फंक्शन ट्रायल के कैच ब्लॉक से, केवल पुनर्खरीद कर सकते हैं।
identity
/ id
मेटाफंक्शन के बारे में बहुत से लोग जानते हैं , लेकिन गैर-टेम्पलेट मामलों के लिए इसके लिए एक अच्छा उपयोग है: घोषणाओं को आसानी से लिखना:
// void (*f)(); // same
id<void()>::type *f;
// void (*f(void(*p)()))(int); // same
id<void(int)>::type *f(id<void()>::type *p);
// int (*p)[2] = new int[10][2]; // same
id<int[2]>::type *p = new int[10][2];
// void (C::*p)(int) = 0; // same
id<void(int)>::type C::*p = 0;
यह C ++ घोषणाओं को डिक्रिप्ट करने में बहुत मदद करता है!
// boost::identity is pretty much the same
template<typename T>
struct id { typedef T type; };
template<typename Ret,typename... Args> using function = Ret (Args...); template<typename T> using pointer = *T;
-> pointer<function<void,int>> f(pointer<function<void,void>>);
या pointer<void(int)> f(pointer<void()>);
याfunction<pointer<function<void,int>>,pointer<function<void,void>>> f;
एक बहुत ही छिपी हुई विशेषता यह है कि आप एक if कंडीशन में वेरिएबल्स को परिभाषित कर सकते हैं, और इसका दायरा केवल if और उसके अन्य ब्लॉक्स पर होगा:
if(int * p = getPointer()) {
// do something
}
कुछ मैक्रोज़ इसका उपयोग करते हैं, उदाहरण के लिए इस तरह से कुछ "लॉक" स्कोप प्रदान करने के लिए:
struct MutexLocker {
MutexLocker(Mutex&);
~MutexLocker();
operator bool() const { return false; }
private:
Mutex &m;
};
#define locked(mutex) if(MutexLocker const& lock = MutexLocker(mutex)) {} else
void someCriticalPath() {
locked(myLocker) { /* ... */ }
}
इसके अलावा BOOST_FACHACH इसे हुड के नीचे उपयोग करता है। इसे पूरा करने के लिए, यह न केवल एक में संभव है, बल्कि एक स्विच में भी:
switch(int value = getIt()) {
// ...
}
और थोड़ी देर में:
while(SomeThing t = getSomeThing()) {
// ...
}
(और यह भी एक शर्त के लिए)। लेकिन मुझे यकीन नहीं है कि क्या ये सब उपयोगी हैं :)
if((a = f()) == b) ...
, लेकिन यह जवाब वास्तव में स्थिति में परिवर्तनशील घोषित करता है।
for(...; int i = foo(); ) ...;
यह शरीर के माध्यम से जाएगा जब तक कि i
यह सही न हो, इसे फिर से शुरू करते हुए। लूप जो आप दिखाते हैं वह केवल एक चर घोषणा का प्रदर्शन कर रहा है, लेकिन एक चर घोषणा नहीं है जो एक साथ एक शर्त के रूप में कार्य करता है :)
कभी-कभी आप अल्पविराम ऑपरेटर का वैध उपयोग करते हैं, लेकिन आप यह सुनिश्चित करना चाहते हैं कि कोई भी उपयोगकर्ता परिभाषित अल्पविराम ऑपरेटर रास्ते में न आए, क्योंकि उदाहरण के लिए आप बाईं और दाईं ओर के बीच अनुक्रम बिंदुओं पर भरोसा करते हैं या यह सुनिश्चित करना चाहते हैं कि वांछित के साथ कुछ भी हस्तक्षेप न करें। कार्रवाई। यह वह जगह है जहाँ void()
खेल में आता है:
for(T i, j; can_continue(i, j); ++i, void(), ++j)
do_code(i, j);
मेरे द्वारा शर्त और कोड के लिए लगाए गए स्थान धारकों की उपेक्षा करें। क्या महत्वपूर्ण है void()
, जो कंपाइलर को बिलिन कॉमा ऑपरेटर का उपयोग करने के लिए मजबूर करता है। यह गुण वर्गों को लागू करते समय उपयोगी हो सकता है, कभी-कभी, भी।
कंस्ट्रक्टर में ऐरे इनिशियलाइज़ेशन। एक वर्ग में उदाहरण के लिए यदि हमारे पास एक सरणी है int
:
class clName
{
clName();
int a[10];
};
हम सरणी में सभी तत्वों को अपने डिफ़ॉल्ट में (यहां सरणी के सभी तत्व शून्य में) को आरंभीकृत कर सकते हैं:
clName::clName() : a()
{
}
ऊओह, मैं इसके बजाय पालतू जानवरों की सूची के साथ आ सकता हूं:
सकारात्मक स्थिति की ओर
आप अनिर्धारित व्यवहार के बिना, और अपेक्षित शब्दार्थ के साथ किसी भी वर्ग के संरक्षित डेटा और फ़ंक्शन सदस्यों तक पहुँच सकते हैं। आगे पढ़िए कैसे। इसके बारे में दोष रिपोर्ट भी पढ़ें ।
आम तौर पर, C ++ आपको किसी वर्ग के ऑब्जेक्ट के गैर-स्थिर संरक्षित सदस्यों तक पहुंचने से मना करता है, भले ही वह वर्ग आपकी आधार श्रेणी हो
struct A {
protected:
int a;
};
struct B : A {
// error: can't access protected member
static int get(A &x) { return x.a; }
};
struct C : A { };
यह निषिद्ध है: आप और संकलक यह नहीं जानते कि संदर्भ वास्तव में किस बिंदु पर है। यह एक C
वस्तु हो सकती है , जिस स्थिति में क्लास के B
पास अपने डेटा के बारे में कोई व्यवसाय और सुराग नहीं है। इस तरह की पहुंच केवल तभी दी जाती है जब x
वह किसी व्युत्पन्न वर्ग का संदर्भ हो या उससे प्राप्त किया गया हो। और यह किसी भी संरक्षित सदस्य को केवल "फेंक-दूर" वर्ग बनाकर पढ़ने की अनुमति दे सकता है, जो उदाहरण के लिए सदस्यों को पढ़ता है std::stack
:
void f(std::stack<int> &s) {
// now, let's decide to mess with that stack!
struct pillager : std::stack<int> {
static std::deque<int> &get(std::stack<int> &s) {
// error: stack<int>::c is protected
return s.c;
}
};
// haha, now let's inspect the stack's middle elements!
std::deque<int> &d = pillager::get(s);
}
निश्चित रूप से, जैसा कि आप देखते हैं कि इससे बहुत अधिक नुकसान होगा। लेकिन अब, सदस्य संकेत इस सुरक्षा को दरकिनार करने की अनुमति देते हैं! मुख्य बिंदु यह है कि सदस्य पॉइंटर का प्रकार उस वर्ग से जुड़ा होता है जिसमें वास्तव में उक्त सदस्य होता है - उस वर्ग के लिए नहीं जो आपने पता लेते समय निर्दिष्ट किया था। यह हमें जाँच को दरकिनार करने की अनुमति देता है
struct A {
protected:
int a;
};
struct B : A {
// valid: *can* access protected member
static int get(A &x) { return x.*(&B::a); }
};
struct C : A { };
और हां, यह std::stack
उदाहरण के साथ भी काम करता है ।
void f(std::stack<int> &s) {
// now, let's decide to mess with that stack!
struct pillager : std::stack<int> {
static std::deque<int> &get(std::stack<int> &s) {
return s.*(pillager::c);
}
};
// haha, now let's inspect the stack's middle elements!
std::deque<int> &d = pillager::get(s);
}
व्युत्पन्न वर्ग में एक प्रयोग घोषणा के साथ यह और भी आसान होने जा रहा है, जो सदस्य के नाम को सार्वजनिक करता है और आधार वर्ग के सदस्य को संदर्भित करता है।
void f(std::stack<int> &s) {
// now, let's decide to mess with that stack!
struct pillager : std::stack<int> {
using std::stack<int>::c;
};
// haha, now let's inspect the stack's middle elements!
std::deque<int> &d = s.*(&pillager::c);
}
एक और छिपी विशेषता यह है कि आप क्लास ऑब्जेक्ट्स को कॉल कर सकते हैं जिन्हें फ़ंक्शन पॉइंटर्स या संदर्भों में परिवर्तित किया जा सकता है। उनके परिणाम के आधार पर अधिभार संकल्प किया जाता है, और तर्क पूरी तरह से अग्रेषित किए जाते हैं।
template<typename Func1, typename Func2>
class callable {
Func1 *m_f1;
Func2 *m_f2;
public:
callable(Func1 *f1, Func2 *f2):m_f1(f1), m_f2(f2) { }
operator Func1*() { return m_f1; }
operator Func2*() { return m_f2; }
};
void foo(int i) { std::cout << "foo: " << i << std::endl; }
void bar(long il) { std::cout << "bar: " << il << std::endl; }
int main() {
callable<void(int), void(long)> c(foo, bar);
c(42); // calls foo
c(42L); // calls bar
}
इन्हें "सरोगेट कॉल फ़ंक्शन" कहा जाता है।
छिपी विशेषताएं:
यदि कोई फ़ंक्शन अपने अपवाद विनिर्देशों में सूचीबद्ध अपवाद को नहीं फेंकता है, लेकिन फ़ंक्शन std::bad_exception
में इसके अपवाद विनिर्देश हैं, तो अपवाद को std::bad_exception
स्वचालित रूप से परिवर्तित और फेंक दिया जाता है। इस तरह आपको कम से कम पता चल जाएगा कि bad_exception
फेंक दिया गया था। और अधिक पढ़ें यहाँ ।
समारोह की कोशिश ब्लॉक
कक्षा के खाके में टाइप किए जाने वाले टंकणों को नष्ट करने का खाका। एक सदस्य टेम्पलेट विशेषज्ञता के नाम एक के बाद दिखाई देता है .
, ->
या ::
ऑपरेटर, और कहा कि नाम स्पष्ट रूप से योग्य टेम्प्लेट पैरामीटर, कीवर्ड टेम्पलेट के साथ उपसर्ग सदस्य टेम्पलेट नाम है। और अधिक पढ़ें यहाँ ।
फ़ंक्शन पैरामीटर डिफॉल्ट को रनटाइम पर बदला जा सकता है। और अधिक पढ़ें यहाँ ।
A[i]
जितना अच्छा काम करता है i[A]
एक वर्ग के अस्थायी उदाहरणों को संशोधित किया जा सकता है! एक गैर-कॉन्स्टेबल सदस्य फ़ंक्शन को अस्थायी ऑब्जेक्ट पर लागू किया जा सकता है। उदाहरण के लिए:
struct Bar {
void modify() {}
}
int main (void) {
Bar().modify(); /* non-const function invoked on a temporary. */
}
और अधिक पढ़ें यहाँ ।
यदि :
टर्नरी ( ?:
) ऑपरेटर अभिव्यक्ति में पहले और बाद में दो अलग-अलग प्रकार मौजूद हैं , तो परिणामी प्रकार का अभिव्यक्ति वह है जो दो में से सबसे सामान्य है। उदाहरण के लिए:
void foo (int) {}
void foo (double) {}
struct X {
X (double d = 0.0) {}
};
void foo (X) {}
int main(void) {
int i = 1;
foo(i ? 0 : 0.0); // calls foo(double)
X x;
foo(i ? 0.0 : x); // calls foo(X)
}
map::operator[]
यदि कुंजी गुम है तो प्रविष्टि बनाता है और डिफ़ॉल्ट रूप से निर्मित प्रविष्टि मान का संदर्भ देता है। तो आप लिख सकते हैं:
map<int, string> m;
string& s = m[42]; // no need for map::find()
if (s.empty()) { // assuming we never store empty values in m
s.assign(...);
}
cout << s;
मुझे आश्चर्य है कि कितने C ++ प्रोग्रामर को यह पता नहीं है।
.find()
।
const map::operator[]
त्रुटि संदेश उत्पन्न करता है"
कार्यों या चरों को एक नाममात्र नामस्थान में रखने static
से उन्हें फाइल स्कोप तक सीमित रखने का उपयोग होता है।
static
वैश्विक दायरे में किसी भी तरह से चित्रित नहीं किया गया है। (संदर्भ के लिए: C ++ 03 .2D.2)
static
उपयोग केवल एक वर्ग-प्रकार या फ़ंक्शन के भीतर किया जाना चाहिए।
क्लास टेम्प्लेट में साधारण मित्र कार्यों को परिभाषित करने पर विशेष ध्यान देने की आवश्यकता है:
template <typename T>
class Creator {
friend void appear() { // a new function ::appear(), but it doesn't
… // exist until Creator is instantiated
}
};
Creator<void> miracle; // ::appear() is created at this point
Creator<double> oops; // ERROR: ::appear() is created a second time!
इस उदाहरण में, दो अलग-अलग तात्कालिकताएं दो समान परिभाषाएं बनाती हैं - ओडीआर का सीधा उल्लंघन
इसलिए हमें यह सुनिश्चित करना चाहिए कि उस टेम्पलेट में परिभाषित किसी भी फ्रेंड फ़ंक्शन के प्रकार में क्लास टेम्प्लेट के टेम्प्लेट पैरामीटर दिखाई दें (जब तक कि हम किसी विशेष फ़ाइल में क्लास टेम्प्लेट के एक से अधिक इंस्टालेशन को रोकना नहीं चाहते हैं, लेकिन यह संभावना नहीं है)। आइए इसे हमारे पिछले उदाहरण की भिन्नता पर लागू करें:
template <typename T>
class Creator {
friend void feed(Creator<T>*){ // every T generates a different
… // function ::feed()
}
};
Creator<void> one; // generates ::feed(Creator<void>*)
Creator<double> two; // generates ::feed(Creator<double>*)
डिस्क्लेमर: मैंने इस सेक्शन को C ++ टेम्प्लेट्स: कम्प्लीट गाइड / सेक्शन 8.4 से पेस्ट किया है
थोड़ा ज्ञात है, लेकिन निम्नलिखित कोड ठीक है
void f() { }
void g() { return f(); }
निम्नलिखित अजीब लग रही के रूप में अस्वेल
void f() { return (void)"i'm discarded"; }
इसके बारे में जानकर आप कुछ क्षेत्रों में लाभ उठा सकते हैं। एक उदाहरण: void
फ़ंक्शंस एक मान नहीं लौटा सकते हैं, लेकिन आप केवल कुछ भी नहीं लौटा सकते हैं, क्योंकि वे गैर-शून्य हो सकते हैं। मान को स्थानीय चर में संग्रहीत करने के बजाय, जिसके लिए एक त्रुटि होगी void
, बस सीधे मान वापस करें
template<typename T>
struct sample {
// assume f<T> may return void
T dosomething() { return f<T>(); }
// better than T t = f<T>(); /* ... */ return t; !
};
तार के वेक्टर में एक फ़ाइल पढ़ें:
vector<string> V;
copy(istream_iterator<string>(cin), istream_iterator<string>(),
back_inserter(V));
vector<string> V((istream_iterator<string>(cin)), istream_iterator<string>());
- दूसरे परम के बाद लापता कोष्ठक
आप बिटफिल्ड को टेम्प्लेट कर सकते हैं।
template <size_t X, size_t Y>
struct bitfield
{
char left : X;
char right : Y;
};
मुझे अभी तक इसके लिए किसी भी उद्देश्य के साथ नहीं आना है, लेकिन यह निश्चित है कि बिल्ली ने मुझे आश्चर्यचकित किया है।
किसी भी प्रोग्रामिंग भाषाओं के सबसे दिलचस्प व्याकरणों में से एक।
इनमें से तीन चीजें एक साथ हैं, और दो पूरी तरह से अलग हैं ...
SomeType t = u;
SomeType t(u);
SomeType t();
SomeType t;
SomeType t(SomeType(u));
सभी लेकिन तीसरा और पांचवां SomeType
स्टैक पर एक ऑब्जेक्ट को परिभाषित करते हैं और इसे इनिशियलाइज़ करते हैं ( u
पहले दो केस के साथ, और चौथे में डिफ़ॉल्ट कंस्ट्रक्शन। तीसरा एक फ़ंक्शन घोषित कर रहा है जो कोई पैरामीटर नहीं लेता है और एक रिटर्न देता है SomeType
। पांचवां भी इसी तरह की घोषणा कर रहा है। एक फ़ंक्शन जो SomeType
नामित नाम के प्रकार से एक पैरामीटर लेता है u
।
आगे की घोषणाओं से छुटकारा:
struct global
{
void main()
{
a = 1;
b();
}
int a;
void b(){}
}
singleton;
के साथ स्विच-स्टेटमेंट लिखना ;: ऑपरेटर:
string result =
a==0 ? "zero" :
a==1 ? "one" :
a==2 ? "two" :
0;
सब कुछ एक ही लाइन पर करना:
void a();
int b();
float c = (a(),b(),1.0f);
मेमरी के बिना शून्य संरचनाएं:
FStruct s = {0};
सामान्यीकरण / रैपिंग कोण- और समय-मान:
int angle = (short)((+180+30)*65536/360) * 360/65536; //==-150
संदर्भ निर्दिष्ट करना:
struct ref
{
int& r;
ref(int& r):r(r){}
};
int b;
ref a(b);
int c;
*(int**)&a = &c;
FStruct s = {};
और भी छोटा है।
main
? मैं सुझाव देता हूं global().main();
और केवल सिंगलटन के बारे में भूल जाओ ( आप केवल अस्थायी के साथ काम कर सकते हैं, जो इसे जीवनकाल विस्तारित हो जाता है )
टर्नरी सशर्त ऑपरेटर ?:
को अपने दूसरे और तीसरे ऑपरेंड के लिए "सहमत" प्रकार (अनौपचारिक रूप से बोलना) की आवश्यकता होती है। लेकिन इस आवश्यकता का एक अपवाद (वाक्य का उद्देश्य) है: या तो दूसरा या तीसरा ऑपरेंड एक फेंक अभिव्यक्ति हो सकता है (जिसमें प्रकार हैvoid
), भले ही अन्य ऑपरेंड के प्रकार की परवाह किए बिना।
दूसरे शब्दों में, कोई ?:
ऑपरेटर का उपयोग करके निम्नलिखित सही ढंग से मान्य C ++ अभिव्यक्ति लिख सकता है
i = a > b ? a : throw something();
BTW, यह तथ्य कि अभिव्यक्ति को फेंकना वास्तव में एक अभिव्यक्ति (प्रकार का void
) है और न कि एक कथन C ++ भाषा की एक और अल्प-ज्ञात विशेषता है। इसका मतलब है, अन्य बातों के अलावा, कि निम्नलिखित कोड पूरी तरह से मान्य है
void foo()
{
return throw something();
}
हालाँकि इसे इस तरह करने का कोई मतलब नहीं है (हो सकता है कि कुछ सामान्य टेम्पलेट कोड में यह काम आए)।
प्रभुत्व नियम उपयोगी है, लेकिन बहुत कम ज्ञात है। यह कहता है कि भले ही एक बेस-क्लास जाली के माध्यम से एक गैर-अद्वितीय पथ में, आंशिक रूप से छिपे हुए सदस्य के लिए नाम-लुकअप अद्वितीय है यदि सदस्य वर्चुअल बेस-क्लास से संबंधित है:
struct A { void f() { } };
struct B : virtual A { void f() { cout << "B!"; } };
struct C : virtual A { };
// name-lookup sees B::f and A::f, but B::f dominates over A::f !
struct D : B, C { void g() { f(); } };
मैंने इसका उपयोग संरेखण-समर्थन को लागू करने के लिए किया है जो कि प्रभुत्व शासन के माध्यम से स्वचालित रूप से सबसे सख्त संरेखण का पता लगाता है।
यह केवल आभासी कार्यों पर ही लागू नहीं होता है, बल्कि टाइप किए गए नामों, स्थिर / गैर-आभासी सदस्यों और कुछ और के लिए भी लागू होता है। मैंने देखा है कि यह मेटा-प्रोग्राम्स में ओवरराइट करने योग्य लक्षणों को लागू करने के लिए उपयोग किया जाता है।
struct C
आपके उदाहरण में शामिल कोई विशेष कारण ...? चीयर्स।