अंतिम अद्यतन:2026-10-12
C++ में फ़ंक्शन टेम्पलेट की जगह क्लास टेम्पलेट¶
हाल ही में टेम्पलेटों का एक बहुत दिलचस्प प्रश्न देखा—— फ़ंक्शन टेम्पलेट और क्लास टेम्पलेट की बुनियाद की पकड़ की अच्छी परीक्षा। नीचे के उदाहरण में क्या समस्या आएगी?
आप आम तौर पर इसे किस तरह ठीक करते हैं?
template <typename T, int R>
struct foo {
foo(const T& v) : value_(v) {}
void bar() {
std::cout << "Generic" << std::endl;
for (int i = 0; i < R; ++i) std::cout << value_ << std::endl;
}
T value_;
};
template <>
void foo<float, 3>::bar() {
std::cout << "Float" << std::endl;
for (int i = 0; i < 3; ++i) std::cout << value_ << std::endl;
}
template <int R>
void foo<double, R>::bar() {
std::cout << "Double" << std::endl;
for (int i = 0; i < R; ++i) std::cout << value_ << std::endl;
}
उत्तर है: आख़िरी दो specializations compile ही नहीं होंगे।
(1) पहला template <> void foo<float, 3>::bar() एक full specialization है, कोई समस्या नहीं;
(2) दूसरा template <int R> void foo<double, R>::bar() partial specialization करना चाहता है—— लेकिन फ़ंक्शन टेम्पलेट की partial specialization की अनुमति नहीं है! कंपाइलर इसे नए फ़ंक्शन टेम्पलेट overload की तरह parse करता है, signature मेल नहीं खाता और सीधे error देता है।
कैसे ठीक करें? क्लास टेम्पलेट की एंट्री¶
C++ का नियम है: फ़ंक्शन टेम्पलेट केवल fully specialize हो सकते हैं, partially नहीं; क्लास टेम्पलेट दोनों तरह से। इसलिए इडियम यह है कि "प्रकार के अनुसार शाखित होने वाली लॉजिक" को फ़ंक्शन टेम्पलेट से निकालकर क्लास टेम्पलेट (प्रायः trait/policy) में डालें और क्लास को partially specialize करें:
template <typename T, int R>
struct bar_impl {
static void run(foo<T, R>& f) {
std::cout << "Generic" << std::endl;
for (int i = 0; i < R; ++i) std::cout << f.value_ << std::endl;
}
};
template <int R>
struct bar_impl<double, R> { // 类模板偏特化:合法!
static void run(foo<double, R>& f) {
std::cout << "Double" << std::endl;
for (int i = 0; i < R; ++i) std::cout << f.value_ << std::endl;
}
};
template <typename T, int R>
void foo<T, R>::bar() { bar_impl<T, R>::run(*this); }
यह STL का भी मानक तरीका है: iterator_traits, __type_traits सब "क्लास टेम्पलेट partial specialization को संभालता है" वाली रणनीति पर हैं।
सारांश¶
(1) फ़ंक्शन टेम्पलेट: केवल overload + full specialization, partial specialization नहीं;
(2) जब "किसी वर्ग के प्रकारों के लिए विशेष implementation" चाहिए, तो implementation को क्लास टेम्पलेट में ले जाएँ और partial specialization/trait से dispatch करें;
(3) C++11 के बाद कई स्थितियों में if constexpr से फ़ंक्शन body में ही सीधे शाखा बना सकते हैं, क्लास टेम्पलेट तक की ज़रूरत नहीं—— लेकिन इसका partial specialization से trade-off आपके विचार के लिए छोड़ रहा हूँ।
संबंधित विषय¶
- C++ डिफ़ॉल्ट कंस्ट्रक्टर से बचना | C++那些事
- C++ क्लास इनिशियलाइज़र लिस्ट इडियम | C++那些事
- C++ copy-and-swap इडियम | C++那些事
- C++ डिपेंडेंसी इंजेक्शन | C++那些事
- C++ enum class स्ट्रॉन्ग टाइप्ड एनम | C++那些事
- C++ Header-Only तथा कार्यान्वयन का पृथक्करण | C++那些事
- C++ लेज़ी इवैल्यूएशन इडियम | C++那些事
- C++ लुकअप टेबल इडियम | C++那些事
- C++ मेंबर पॉइंटर तथा टाइप जानकारी | C++那些事
- C++ Mixin इडियम | C++那些事