💡 सारांश:std::function अंदर से कैसे काम करता है (टाइप इरेज़र, छोटा बफ़र ऑप्टिमाइज़ेशन) उदाहरणों के साथ, और C++23 का std::move_only_function कब std::function की जगह लेता है।
अंतिम अद्यतन:2026-10-24
C++ std::function विस्तार से¶
हाल ही में C++ कोड लिखते समय is_function का उपयोग किया, फिर चलते-चलते इसका सोर्स कोड इम्प्लीमेंटेशन देखा और कुछ बातें सामने आईं — पहले हमने तीन डॉट्स ... सीखे थे, तो छह डॉट्स ...... क्या हैं ये पता है?
उसी तरह, अगर ऐसा कोड हो:
तो क्या पता है इसका मतलब?
आइए गहराई में उतरते हैं!
1.छह डॉट्स¶
छह डॉट्स को हम आमतौर पर two ellipsis operators कहते हैं, हम छह डॉट्स को तोड़ सकते हैं, जिससे निम्नलिखित तीन स्थितियाँ मिलती हैं
template <typename... Args> void foo1(Args......)
template <typename... Args> void foo2(Args... ...)
template <typename... Args> void foo3(Args..., ...)
अब देखने में आसान है, आइए std::is_function का कोड देखें।
2.is_function इम्प्लीमेंटेशन विवरण¶
std::is_function का इम्प्लीमेंटेशन primary टेम्पलेट और दो partial specialization से जुड़ा है:
// 主模板,假设提供的类型不是函数类型
template<typename T>
struct is_function : std::false_type {};
// 偏特化,用于正常的函数类型
template<typename Ret, typename... Args>
struct is_function<Ret(Args...)> : std::true_type {};
// 偏特化,用于变参函数类型
template<typename Ret, typename... Args>
struct is_function<Ret(Args......)> : std::true_type {};
- primary टेम्पलेट मानता है कि दिया गया टाइप फ़ंक्शन टाइप नहीं है, और परिणाम के रूप में
std::false_typeदेता है। - पहला partial specialization सामान्य फ़ंक्शन टाइप के लिए है, जिसमें
Retरिटर्न टाइप औरArgs...पैरामीटर टाइप्स दर्शाता है। अगर दिया गया टाइप इस फ़ंक्शन सिग्नेचर से मैच करता है, तो परिणामstd::true_typeहोता है। - दूसरा partial specialization variadic फ़ंक्शन टाइप के लिए है, जिसमें एलिप्सिस दर्शाता है कि फ़ंक्शन में पैरामीटर्स की संख्या बदल सकती है। इसी तरह, अगर दिया गया टाइप इस फ़ंक्शन सिग्नेचर से मैच करता है, तो परिणाम
std::true_typeहोता है।
3.उपयोग का उदाहरण¶
आख़िर में std::is_function का एक उपयोग उदाहरण:
#include <iostream>
#include <type_traits>
int func(int x, int y) { return x + y; }
int vararg_func(int x, ...) { return x; }
int main() {
std::cout << std::boolalpha;
std::cout << "Is func a function? " << std::is_function<decltype(func)>::value << std::endl;
std::cout << "Is vararg_func a function? " << std::is_function<decltype(vararg_func)>::value << std::endl;
return 0;
}
यह आउटपुट देगा:
क्या सीख लिया, इस सेक्शन का अंत~
C++23 std::move_only_function vs std::function¶
आपने अभी पढ़ा टाइप इरेज़र की एक छिपी कीमत है: std::function माँगता है कि लिपटा हुआ invocable कॉपी-कंस्ट्रक्टिबल हो — कॉपी करने लायक रैपर उसके अनुबंध का हिस्सा है। lambda में std::unique_ptr कैप्चर करके स्टोर करने की कोशिश करें — कंपाइलर मना कर देगा:
auto make_sink() {
auto ptr = std::make_unique<std::vector<int>>(42);
return [ptr = std::move(ptr)] { return ptr->size(); }; // move-only closure
}
// std::function<std::size_t()> f = make_sink(); // ERROR: closure not copyable
std::move_only_function<std::size_t()> g = make_sink(); // OK since C++23
std::move_only_function (C++23, हेडर
कैसे चुनें: invocable कॉपी करना सस्ता हो और पुराने APIs माँगते हों तो std::function रखें; closure किसी अनन्य चीज़ की मालिक हो तो std::move_only_function पर जाएँ। यह भी याद रखें कि std::function असाइनमेंट पर closure कॉपी करता है — भारी कैप्चर पर यह असली लागत है, जिससे move_only_function बचाता है। परफ़ॉर्मेंस-संवेदनशील जगहों पर सादा टेम्पलेट पैरामीटर दोनों से आगे है: न इरेज़र, न अप्रत्यक्ष कॉल, पूरी तरह inline।
अक्सर पूछे जाने वाले प्रश्न¶
std::function और std::move_only_function में क्या अंतर है?¶
std::function कॉपी करने योग्य invocables माँगता है और असाइनमेंट पर कॉपी करता है; std::move_only_function (C++23) move-only invocables लेता है और सिर्फ़ मूव करता है। बाक़ी व्यवहार और कॉल सिंटैक्स एक जैसे हैं।
std::function unique_ptr कैप्चर करने वाली lambda क्यों नहीं रख पाता?¶
क्योंकि std::function को संग्रहीत invocable की कॉपी बनाने की क्षमता चाहिए, और unique_ptr जैसा move-only टाइप कैप्चर होते ही closure का कॉपी कंस्ट्रक्टर डिलीट हो जाता है। std::move_only_function या टेम्पलेट पैरामीटर इस्तेमाल करें।
क्या std::move_only_function, std::function से तेज़ है?¶
यह कॉपी का ख़र्च और कुछ बहीखाता बचाता है, पर दोनों टाइप इरेज़र और अप्रत्यक्ष कॉल से गुज़रते हैं। अगर कॉल साइट टाइप जानती है, तो invocable को टेम्पलेट पैरामीटर बनाएँ — वही असली तेज़ रास्ता है।
संबंधित विषय¶
- C++ प्योर वर्चुअल फ़ंक्शन और एब्स्ट्रैक्ट क्लास | C++那些事
- C++ assert | C++那些事
- C++ bit-field | C++那些事
- C भाषा से C++ पॉलीमॉर्फ़िज़्म | C++那些事
- C++ const विस्तार से: कॉन्स्टेंट, const पॉइंटर vs पॉइंटर-टू-const | C++那些事
- C++ const परिवार | C++那些事
- C++ dereference ऑपरेटर * | C++那些事
- C++ इनिशियलाइज़ेशन और असाइनमेंट | C++那些事
- C++ multiple return values लिखने के तरीके | C++那些事
- C++ mutable कीवर्ड | C++那些事