खोज…


परिचय

constexpr एक ऐसा कीवर्ड है जिसका उपयोग चर के मान को स्थिर अभिव्यक्ति के रूप में चिह्नित करने के लिए किया जा सकता है, एक ऐसा कार्य जो निरंतर अभिव्यक्ति में संभावित रूप से उपयोग किया जा सकता है, या (C ++ 17 के बाद से) यदि एक बयान के रूप में संकलित होने के लिए चयनित इसकी केवल एक शाखा है।

टिप्पणियों

C ++ 11 में constexpr कीवर्ड जोड़ा गया था, लेकिन कुछ वर्षों से C ++ 11 मानक प्रकाशित होने के बाद, सभी प्रमुख संकलकों ने इसका समर्थन नहीं किया। उस समय जब C ++ 11 मानक प्रकाशित हुआ था। C ++ 14 के प्रकाशन के समय तक, सभी प्रमुख कंपाइलर constexpr समर्थन constexpr

constexpr चरों

एक चर घोषित constexpr परोक्ष है const और अपने मूल्य के लिए एक निरंतर अभिव्यक्ति के रूप में इस्तेमाल किया जा सकता है।

#define साथ तुलना

एक constexpr #define आधारित संकलन-समय अभिव्यक्तियों के लिए टाइप-सुरक्षित प्रतिस्थापन है। constexpr के साथ संकलन-समय मूल्यांकन अभिव्यक्ति को परिणाम के साथ बदल दिया जाता है। उदाहरण के लिए:

सी ++ 11
int main()
{
   constexpr int N = 10 + 2;
   cout << N;
}

निम्नलिखित कोड का उत्पादन करेगा:

cout << 12;

एक प्री-प्रोसेसर आधारित संकलन-समय मैक्रो अलग होगा। विचार करें:

#define N 10 + 2

int main()
{
    cout << N;
}

उत्पादन करेंगे:

cout << 10 + 2;

जो स्पष्ट रूप से cout << 10 + 2; परिवर्तित हो जाएगा cout << 10 + 2; । हालांकि, कंपाइलर को अधिक काम करना होगा। इसके अलावा, यह एक समस्या पैदा करता है अगर सही तरीके से उपयोग नहीं किया जाता है।

उदाहरण के लिए ( #define साथ):

cout << N * 2;

रूपों:

cout << 10 + 2 * 2; // 14

लेकिन पहले से मूल्यांकन किया गया constexpr सही ढंग से 24

के साथ तुलना const

एक const वैरिएबल एक वैरिएबल है, जिसे स्टोरेज के लिए मेमोरी की जरूरत होती है। एक constexpr नहीं है। एक constexpr संकलित समय का निरंतर उत्पादन करता है, जिसे बदला नहीं जा सकता है। आप तर्क दे सकते हैं कि const को भी नहीं बदला जा सकता है। पर विचार करें:

int main()
{
   const int size1 = 10;
   const int size2 = abs(10);

   int arr_one[size1]; 
   int arr_two[size2]; 
}

अधिकांश संकलक के साथ दूसरा कथन विफल हो जाएगा (उदाहरण के लिए, जीसीसी के साथ काम कर सकते हैं)। किसी भी सरणी का आकार, जैसा कि आप जानते हैं, एक स्थिर अभिव्यक्ति होना चाहिए (यानी संकलन-समय मूल्य में परिणाम)। दूसरे चर size2 को कुछ मान दिया गया है जो रनटाइम पर तय किया गया है (भले ही आप जानते हैं कि यह 10 , संकलक के लिए यह संकलन-समय नहीं है)।

इसका मतलब यह है कि एक const सही संकलन-समय स्थिर हो सकता है या नहीं। आप गारंटी नहीं दे सकते या लागू नहीं कर सकते हैं कि एक विशेष const वैल्यू बिल्कुल संकलन-समय है। आप #define उपयोग कर सकते हैं, लेकिन इसके अपने नुकसान हैं।

इसलिए बस उपयोग करें:

सी ++ 11
int main()
{
    constexpr int size = 10;

    int arr[size];
}

एक constexpr अभिव्यक्ति को एक संकलन-समय मूल्य का मूल्यांकन करना चाहिए। इस प्रकार, आप उपयोग नहीं कर सकते हैं:

सी ++ 11
constexpr int size = abs(10);

जब तक समारोह ( abs ) है अपने आप में एक लौटने constexpr

सभी बुनियादी प्रकारों को constexpr साथ आरंभ किया जा सकता है।

सी ++ 11
constexpr bool FailFatal = true;
constexpr float PI = 3.14f;
constexpr char* site= "StackOverflow";

दिलचस्प है, और आसानी से, आप auto उपयोग भी कर सकते हैं:

सी ++ 11
constexpr auto domain = ".COM";  // const char * const domain = ".COM"
constexpr auto PI = 3.14;        // constexpr double

बाधा कार्य

एक फ़ंक्शन जिसे constexpr घोषित किया constexpr वह अंतर्निहित रूप से इनलाइन होता है और ऐसे फ़ंक्शन को कॉल करता है जो संभावित रूप से निरंतर अभिव्यक्ति देता है। उदाहरण के लिए, निम्न फ़ंक्शन, यदि निरंतर अभिव्यक्ति तर्कों के साथ कहा जाता है, तो एक स्थिर अभिव्यक्ति भी मिलती है:

सी ++ 11
constexpr int Sum(int a, int b)
{
    return a + b;
}

इस प्रकार, फ़ंक्शन कॉल का परिणाम सरणी बाउंड या टेम्प्लेट तर्क के रूप में, या एक constexpr चर को इनिशियलाइज़ करने के लिए उपयोग किया जा सकता है:

सी ++ 11
int main()
{
    constexpr int S = Sum(10,20);
   
    int Array[S];
    int Array2[Sum(20,30)]; // 50 array size, compile time
}

ध्यान दें कि यदि आप फ़ंक्शन के रिटर्न प्रकार विनिर्देश से constexpr को constexpr , तो S को असाइनमेंट काम नहीं करेगा, क्योंकि S एक constexpr वेरिएबल है, और इसे एक संकलन-समय constexpr सौंपा जाना चाहिए। इसी तरह, सरणी का आकार भी नहीं एक निरंतर अभिव्यक्ति, हो सकता है अगर समारोह Sum नहीं है constexpr

constexpr कार्यों के बारे में दिलचस्प बात यह है कि आप इसे सामान्य कार्यों की तरह भी उपयोग कर सकते हैं:

सी ++ 11
int a = 20;
auto sum = Sum(a, abs(-20));

Sum अब एक constexpr फ़ंक्शन नहीं होगा, इसे एक सामान्य फ़ंक्शन के रूप में संकलित किया जाएगा, चर (गैर-स्थिर) तर्क ले रहा है, और गैर-निरंतर मान लौटा रहा है। आपको दो फ़ंक्शन लिखने की आवश्यकता नहीं है।

इसका अर्थ यह भी है कि यदि आप ऐसे कॉल को नॉन-कास्ट वैरिएबल में असाइन करने का प्रयास करते हैं, तो यह संकलन नहीं करेगा:

सी ++ 11
int a = 20;
constexpr auto sum = Sum(a, abs(-20));

कारण सरल है: constexpr को केवल एक संकलन-समय स्थिर सौंपा जाना चाहिए। हालाँकि, उपरोक्त फ़ंक्शन कॉल Sum एक गैर- constexpr बनाता है (आर-वैल्यू नॉन- constexpr है, लेकिन एल-वैल्यू खुद को constexpr होने की घोषणा कर रहा है)।


constexpr फ़ंक्शन को एक संकलन-समय स्थिरांक भी लौटना चाहिए । निम्नलिखित संकलन नहीं होगा:

सी ++ 11
constexpr int Sum(int a, int b)
{
    int a1 = a;     // ERROR
    return a + b;
}

क्योंकि a1 एक नॉन-कॉन्स्ट्रेक्स वैरिएबल है , और फंक्शन को एक सही constexpr फंक्शन होने से constexpr है। यह बनाना constexpr और यह बताए a भी काम नहीं - के बाद से का मूल्य a (भेजे पैरामीटर) अभी भी अभी तक ज्ञात नहीं है:

सी ++ 11
constexpr int Sum(int a, int b)
{
   constexpr int a1 = a;     // ERROR
   ..

इसके अलावा, निम्नलिखित भी संकलित नहीं करेंगे:

सी ++ 11
constexpr int Sum(int a, int b)
{
   return abs(a) + b; // or abs(a) + abs(b)
}

चूंकि abs(a) एक निरंतर अभिव्यक्ति (यहां तक कि नहीं है abs(10) होगा काम नहीं है, क्योंकि abs एक नहीं लौटा रहा है constexpr int !

इस बारे में क्या?

सी ++ 11
constexpr int Abs(int v)
{
    return v >= 0 ? v : -v;
}

constexpr int Sum(int a, int b)
{
    return Abs(a) + b;
}

हम अपने गढ़ी Abs समारोह जो एक है constexpr , और के शरीर Abs भी किसी भी नियम का उल्लंघन नहीं करती। इसके अलावा, कॉल साइट पर ( Sum अंदर), अभिव्यक्ति एक constexpr मूल्यांकन constexpr । इसलिए, Sum(-10, 20) को कॉल करने के लिए 30 परिणामस्वरूप एक संकलन-समय स्थिर अभिव्यक्ति होगी।

स्टेटिक अगर स्टेटमेंट

सी ++ 17

if constexpr स्टेटमेंट का उपयोग सशर्त रूप से संकलित कोड के लिए किया जा सकता है। स्थिति एक स्थिर अभिव्यक्ति होनी चाहिए। चयनित शाखा को खारिज नहीं किया जाता है किसी टेम्प्लेट के अंदर खारिज किया गया स्टेटमेंट तत्काल नहीं है। उदाहरण के लिए:

template<class T, class ... Rest>
void g(T &&p, Rest &&...rs)
{
  // ... handle p
  if constexpr (sizeof...(rs) > 0)
    g(rs...);  // never instantiated with an empty argument list
}

इसके अलावा, चर और फ़ंक्शन जो केवल खारिज किए गए बयानों के अंदर उपयोग किए जाते हैं, उन्हें परिभाषित करने की आवश्यकता नहीं होती है, और फ़ंक्शन रिटर्न प्रकार कटौती के लिए त्याग किए गए return स्टेटमेंट का उपयोग नहीं किया जाता है।

if constexpr से अलग है #ifdef#ifdef सशर्त रूप से कोड संकलित करता है, लेकिन केवल उन परिस्थितियों पर आधारित है जिनका मूल्यांकन प्रीप्रोसेसिंग समय पर किया जा सकता है। उदाहरण के लिए, #ifdef को टेम्पलेट पैरामीटर के मूल्य के आधार पर सशर्त रूप से संकलित कोड के लिए इस्तेमाल नहीं किया जा सकता है। दूसरी ओर, if constexpr इस्तेमाल वाक्यगत रूप से अमान्य कोड को छोड़ने के लिए नहीं किया जा सकता है, जबकि #ifdef कर सकता है।

if constexpr(false) {
    foobar;  // error; foobar has not been declared
    std::vector<int> v("hello, world");  // error; no matching constructor
}


Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow