विषय पर बढ़ें

💡 सारांश:C++ की पूरी const परिवार: const बनाम constexpr और constinit, consteval और const सदस्य, साथ ही C++23 का deducing this चार const/ref ओवरलोड्स को एक ही फ़ंक्शन में कैसे समेट देता है।

अंतिम अद्यतन:2026-10-24

C++ const परिवार

रूपरेखा

  • const
  • constexpr
  • C++20
  • consteval
  • constinit

नोट: इस लेख के सभी कोड उदाहरण Knowledge Planet पर दिए गए हैं।

1.const

const C++/C सीखते समय सबसे पहले मिलने वाले कीवर्ड्स में से एक है, आमतौर पर cv-qualifier की तरह उपयोग होता है, जो दर्शाता है कि ऑब्जेक्ट immutable है। यह compile-time evaluation की गारंटी नहीं देता, कब evaluation होगा यह कंपाइलर तय करता है। उदाहरण के लिए:

const int a = 1; // 编译时
const auto x = getdata(); // 运行时

const कभी-कभी compile-time constant expression में उपयोग हो सकता है, लेकिन कुछ अपवाद हैं, जैसे:

const double count_1 = 3.3;
std::array<double, static_cast<int>(count_1)> moreDoubles1 {1.1, 2.2, 3.3};

इस स्थिति में error आएगा: the value of 'count_1' is not usable in a constant expression

लेकिन ऐसा करना सही है:

const int count = 3;
std::array<double, count> doubles {1.1, 2.2, 3.3};

इसका मूल कारण compile-time expression evaluation है, इसलिए C++11 ने constexpr लाया।

2.constexpr

constexpr से निर्दिष्ट किया जा सकता है कि वेरिएबल की वैल्यू constant expression में आ सकती है, इसके लिए बस पिछले उदाहरण का const बदलकर constexpr करना है, फिर यह सही चलेगा।

constexpr double count_2 = 3.3;
std::array<double, static_cast<int>(count_2)> moreDoubles2 {1.1, 2.2, 3.3}; 

constexpr का मतलब यह नहीं कि यह केवल compile time पर ही चलेगा। इसका असली अर्थ है कि यह compile time पर calculate हो सकता है, पर अगर runtime में constexpr वेरिएबल या फ़ंक्शन का उपयोग किया जाए, तो यह runtime पर भी निष्पादित हो सकता है।

उदाहरण के लिए: result1 और result2 बिल्कुल अलग हैं, result1 compile time पर calculate होता है, जबकि result2 runtime पर, एक सवाल: क्या आप जानते हैं क्यों?

इसलिए constexpr लिखा फ़ंक्शन ज़रूरी नहीं कि हमेशा compile time पर ही calculate हो।

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

int main() {
    constexpr int result1 = compileTimeSum(3, 5); 
    int x = 10;
    int result2 = compileTimeSum(x, 20);  
    return 0;
}

तो इसकी गारंटी कौन देता है? तब C++20 आया।

3.C++20

3.1 consteval

consteval ऊपर की समस्या हल करता है, यह केवल फ़ंक्शन पर उपयोग होता है और सभी कॉल को compile time पर होने पर मजबूर करता है। अगर हम ऊपर का constexpr बदलकर consteval कर दें, तो result2 का क्या होगा?

तो error आएगा: call to consteval function 'compileTimeSum(x, 20)' is not a constant expression

consteval int compileTimeSum(int a, int b) {
    return a + b;
}

int main() {
    constexpr int result1 = compileTimeSum(3, 5); 
    int x = 10;
    int result2 = compileTimeSum(x, 20);  
    return 0;
}

अगर consteval को वेरिएबल पर उपयोग करें, तो भी error आएगा: error: a variable cannot be declared 'consteval'।

https://en.cppreference.com/w/cpp/language/consteval

3.2 constinit

constinit static या thread local वेरिएबल को constant initialization पर मजबूर कर सकता है।

  • constexpr, consteval के साथ उपयोग नहीं हो सकता
  • यह एक non-type specifier है, इसका काम assert जैसा है
  • गारंटी देता है कि वेरिएबल static initialize होगा
  • केवल static या thread_local पर उपयोग होता है

उदाहरण के लिए: नीचे का compile error देगा: error: 'constinit' can only be applied to a variable with static or thread storage duration

constinit int a = 100;  
int main() {  
      ++a; 
      constinit auto b = 100;  // error
      // b has thread storage duration
      constinit thread_local auto b = 100;
}

C++23 deducing this: const/ref ओवरलोड्स एक ही बार लिखें

const परिवार में आगे बढ़ते हुए लगभग हर कोई एक ही दीवार से टकराता है: const और ग़ैर-const ऑब्जेक्ट्स, lvalue और rvalue — सब पर सही व्यवहार करने वाले getter को चार तक लगभग समान ओवरलोड्स लिखने पड़ते हैं, और जिस दिन कोई सिर्फ़ एक को संपादित करता है, वे चुपचाप अलग होने लगते हैं।

C++23 का «deducing this» (स्पष्ट ऑब्जेक्ट पैरामीटर, प्रपोज़ल P0847) यह दुहराव मिटा देता है। मेंबर फ़ंक्शन अपने ही ऑब्जेक्ट को स्पष्ट पैरामीटर के रूप में घोषित करता है; कंपाइलर उसका टाइप constness और वैल्यू कैटेगरी सहित निकालता है, और एक ही टेम्पलेट चारों केस संभाल लेता है:

class Widget {
    int value_{42};

public:
    // Before C++23 you needed up to four overloads:
    //   int&  get() &       { return value_; }
    //   int   get() const&  { return value_; }
    //   int&& get() &&      { return std::move(value_); }
    //   ...
    // C++23 deducing this — one template covers them all:
    template <typename Self>
    auto&& get(this Self&& self) {
        return std::forward<Self>(self).value_;
    }
};

const lvalue पर get() कॉल करने पर Self const Widget& निकलता है; rvalue पर Widget&&, और std::forward मूव कर देता है। क्या const होना चाहिए — यह फ़ैसला अब भी पहले समझाई गई जानकारी का काम है; deducing this बस दोहराव हटाता है।

यह फ़ीचर CRTP के दो पुराने काम — व्यवहार मिलाना और व्युत्पन्न टाइप निकालना — बिना बेस-क्लास टेम्पलेट बॉयलरप्लेट के भी संभाल लेता है। सपोर्ट: GCC 14+, Clang 18+, MSVC VS 2022 17.2 से।

अक्सर पूछे जाने वाले प्रश्न

क्या deducing this const ओवरलोड्स की जगह ले सकता है?

आम मामले में हाँ। Self&& पर एक टेम्पलेट std::forward के साथ &, const&, && और const&& सब पर सही चलता है। अलग ओवरलोड तभी लिखें जब क्वालिफ़िकेशन के हिसाब से व्यवहार सचमुच अलग हो — जो दुर्लभ है।

कौन से कंपाइलर deducing this सपोर्ट करते हैं?

GCC 14 और ऊपर, Clang 18 और ऊपर, MSVC Visual Studio 2022 17.2 से। यह C++23 फ़ीचर है, -std=c++23 (पुराने ड्राइवर पर c++2b) के साथ कंपाइल करें।

क्या deducing this, CRTP जैसा ही है?

ओवरलैप है: दोनों सबसे व्युत्पन्न टाइप निकालते हैं। Deducing this को बेस टेम्पलेट की ज़रूरत नहीं, यह lambda पर भी चलता है (रिकर्सिव lambda!), और पदानुक्रम साफ़ रहता है; जब मिक्सिन का पुन:प्रयोज्य बेस क्लास होना ज़रूरी हो, तब CRTP उपयोगी है।

संबंधित विषय

टिप्पणियाँ