विषय पर बढ़ें

💡 सारांश:C++20 lambda (भाग 1): टेम्पलेट सिंटैक्स और टाइप प्रतिबंध, और C++23 का deducing this std::function के बिना recursive lambda को एक लाइन में कैसे लिखा जाता है।

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

C++20 Lambda एक्सप्रेशन (भाग 1)

C++20 - lambda टेम्प्लेट

C++14 generic lambda एक्सप्रेशन का समर्थन करता है, जिससे lambda किसी भी प्रकार के पैरामीटर ले सकता है, उदाहरण के लिए:

auto func = [](auto a, auto b) {
    return a + b;
};

इसे इस तरह विस्तारित किया जाता है:

struct Func {
    template <typename T1, typename T2>
    auto operator()(T1 a, T2 b) const {
        return a + b;
    }
};

लेकिन नीचे दिए गए कुछ विस्तार रूप हासिल नहीं किए जा सकते:

पहला प्रकार: समान प्रकार

template <class T>
auto operator()(T t1, T t2) const;

दूसरा प्रकार: केवल std::array

template <class T, std::size_t N>
auto operator()(std::array<T, N> const &) const; 

तीसरा प्रकार: कोई deduction नहीं

template <class T>
auto operator()() const;

C++14 lambdas बढ़िया हैं, लेकिन C++20 हमें इन स्थितियों को आसानी से क्रियान्वयन करने की अनुमति देता है। C++20, lambda एक्सप्रेशन को परिभाषा में टेम्प्लेट प्रकार पैरामीटर उपयोग करने की अनुमति देता है, मूल सिंटैक्स इस प्रकार है:

[]<typename T>(){}

नीचे कुछ उदाहरणों से इसके फ़ायदे समझाते हैं।

1. प्रकार सीमांकन

नीचे जैसे उदाहरण में, C++14 में हम यह कोड लिख सकते हैं, लेकिन उपयोग के समय भीतर आने वाला vector ही हो, यह गारंटीड नहीं, तो अपेक्षित व्यवहार से भिन्नता होगी, और त्रुटि पैदा होगी।

auto print = [](auto vec) {
  for (auto x : vec) {
    std::cout << x << std::endl;
  }
};

C++20 के बाद, हम इसके प्रकार को सीमित कर सकते हैं:

auto print2 = []<typename T>(std::vector<T>& vec){
    //使用 std::vector<T> 执行操作
};

तो सवाल उठता है, एक इंटरव्यू प्रश्न: क्या आप जानते हैं C++14 में vector सीमित करने के लिए सुरक्षा कैसे सुनिश्चित करें?

2. परफ़ेक्ट फ़ॉरवर्डिंग

C++20 में आप परफ़ेक्ट फ़ॉरवर्डिंग बहुत आसानी से उपयोग कर सकते हैं, उदाहरण के लिए:

auto lambdaFunc = []<typename T>(T&& number) {
  processFunction(std::forward<T>(number));
};

तो सवाल उठता है, C++14 की तुलना में इसका क्या फ़ायदा है? या कहें, C++14 में परफ़ेक्ट फ़ॉरवर्डिंग क्रियान्वयन करने के लिए क्या करना पड़ता है?

यह सेक्शन समाप्त

Recursive Lambda और deducing this (C++23)

साधारण lambda अपना नाम नहीं ले सकती, इसलिए रिकर्शन के लिए lambda को std::function में रखना (अलोकेशन, अप्रत्यक्ष कॉल) या Y-combinator में लपेटना (चतुर, पर अपठनीय) पड़ता था। C++23 के स्पष्ट ऑब्जेक्ट पैरामीटर — वही deducing this फ़ीचर — इसे सुंदर तरीके से हल करते हैं: lambda ख़ुद को पहला पैरामीटर मानकर प्राप्त करती है:

// C++23 explicit object parameter: the lambda receives itself
auto factorial = [](this auto self, int n) -> long long {
    return n <= 1 ? 1 : n * self(n - 1);
};

static_assert(factorial(10) == 3628800);

// before C++23 you needed std::function (heavy) or a Y-combinator (clever)

self पैरामीटर हर कॉल पर डिड्यूस होता है, इसलिए जेनरिक रिकर्शन भी चलता है: एक ही lambda किसी भी टाइप पर रिकर्स कर सकती है, और दो lambda एक-दूसरे को ख़ुद को पास करके म्यूचुअल रिकर्शन भी कर सकती हैं। कंपाइलर self के भीतर देख पाता है, इसलिए ये कॉल ऐसे inline होते हैं जैसे आपने नाम वाला फ़ंक्शन लिखा हो।

कंपाइलर सपोर्ट: GCC 14+, Clang 18+, MSVC VS 2022 17.2 से — -std=c++23 के साथ कंपाइल करें।

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

C++ में recursive lambda कैसे लिखें?

C++23 से lambda को स्पष्ट ऑब्जेक्ट पैरामीटर दें: [](this auto self, int n) { ... self(n-1) ... }। इससे पहले std::function, Y-combinator, या सीधे नाम वाला फ़ंक्शन।

deducing this वाली recursive lambda सामान्य फ़ंक्शन जितनी तेज़ है?

व्यवहार में हाँ: कंपाइलर self के ज़रिए कॉल specialize करके inline कर सकता है, C++23 से पहले वाले std::function के अप्रत्यक्ष कॉल के विपरीत।

क्या deducing this जेनरिक lambda के साथ चलता है?

हाँ। self हर कॉल पर auto&& रूप में डिड्यूस होता है, इसलिए वही lambda अलग-अलग टाइप पर रिकर्स कर सकती है, और दो lambda ख़ुद को पास करके एक-दूसरे को भी कॉल कर सकती हैं।

संबंधित विषय

टिप्पणियाँ