मैं एक बड़ी कक्षा को पुन: सक्रिय करने की प्रक्रिया में हूं - चलो इसे Big
पर कॉल करें - इसमें बड़ी संख्या में कॉपी-पेस्ट कोड है। इस कॉपी-पेस्ट कोड में से अधिकांश switch
case
एस में मौजूद है जहां केवल शामिल प्रकार अलग-अलग होते हैं। यह कोड कक्षा के enum
सदस्य चर के आधार पर स्विच कर रहा है जिसका मूल्य केवल रनटाइम पर जाना जाता है।टेम्पलेट पैरामीटर के साथ सी ++ फ़ंक्शन प्रेषण
इसमें सुधार करने का मेरा प्रयास कक्षा है जिसमें static
फ़ंक्शन के माध्यम से lookup()
नामक उचित टाइप किए गए फ़ंक्शन दिखते हैं। वास्तविक कार्य करने वाले फ़ंक्शंस को हमेशा go()
कहा जाता है और उन्हें एक रैपर क्लास टेम्पलेट में परिभाषित किया जाना चाहिए (जिसका एकमात्र पैरामीटर रनटाइम enum
वर्तमान में चालू होने वाला मान है)। go()
फ़ंक्शन टेम्पलेट फ़ंक्शन स्वयं हो सकते हैं या नहीं भी हो सकते हैं।
यहां कोड का एक आसवित संस्करण है। लंबाई के लिए मेरी माफ़ी, लेकिन यह उतना छोटा था जितना कि मैं इसे महत्वपूर्ण संदर्भ खोने के बिना प्राप्त कर सकता था।
#include <cassert>
class Big
{
public:
enum RuntimeValue { a, b };
Big(RuntimeValue rv) : _rv(rv) { }
bool equals(int i1, int i2)
{
return Dispatcher<Equals, bool(int, int)>::lookup(_rv)(i1, i2);
}
template<typename T>
bool isConvertibleTo(int i)
{
return Dispatcher<IsConvertibleTo, bool(int)>::lookup<T>(_rv)(i);
}
private:
template<RuntimeValue RV>
struct Equals
{
static bool go(int i1, int i2)
{
// Pretend that this is some complicated code that relies on RV
// being a compile-time constant.
return i1 == i2;
}
};
template<RuntimeValue RV>
struct IsConvertibleTo
{
template<typename T>
static bool go(int i)
{
// Pretend that this is some complicated code that relies on RV
// being a compile-time constant.
return static_cast<T>(i) == i;
}
};
template<template<RuntimeValue> class FunctionWrapper, typename Function>
struct Dispatcher
{
static Function * lookup(RuntimeValue rv)
{
switch (rv)
{
case a: return &FunctionWrapper<a>::go;
case b: return &FunctionWrapper<b>::go;
default: assert(false); return 0;
}
}
template<typename T>
static Function * lookup(RuntimeValue rv)
{
switch (rv)
{
case a: return &FunctionWrapper<a>::go<T>;
case b: return &FunctionWrapper<b>::go<T>;
default: assert(false); return 0;
}
}
// And so on as needed...
template<typename T1, typename T2>
static Function * lookup(RuntimeValue rv);
};
RuntimeValue _rv;
};
int main()
{
Big big(Big::a);
assert(big.equals(3, 3));
assert(big.isConvertibleTo<char>(123));
}
यह ज्यादातर, काम करता है सिवाय इसके कि:
- यह बनाता है और विजुअल C++ 9 (2008) के तहत ठीक काम करता है, लेकिन जीसीसी 4.8 के तहत यह
lookup()
का कार्य-टेम्पलेट अधिभार में संकलन त्रुटियों में परिणाम । - यह आवश्यक है कि
lookup()
का एक नया फ़ंक्शन-टेम्पलेट अधिभारgo()
में समर्थन करने के लिए हर नए फ़ंक्शन टेम्पलेट पैरामीटर के लिए लिखा जाए। - यह बोझिल और उपयोग करने में भ्रमित है।
Big.cpp: In static member function 'static Function* Big::Dispatcher<FunctionWrapper, Function>::lookup(Big::RuntimeValue)': Big.cpp(66,65) : error: expected primary-expression before '>' token case a: return &FunctionWrapper<a>::go<T>; ^ Big.cpp(66,66) : error: expected primary-expression before ';' token case a: return &FunctionWrapper<a>::go<T>; ^ Big.cpp(67,65) : error: expected primary-expression before '>' token case b: return &FunctionWrapper<b>::go<T>; ^ Big.cpp(67,66) : error: expected primary-expression before ';' token case b: return &FunctionWrapper<b>::go<T>; ^
मेरा प्रश्न दोहरा है::
यहाँ त्रुटियों कि जीसीसी के अंतर्गत होने वाली हैं
- क्यों इस जीसीसी के तहत निर्माण करने के लिए विफल हो रहा है, और मैं इसे कैसे ठीक करूं?
- क्या ऐसा करने के लिए कोई बेहतर (यानी, कम बोझिल और भ्रमित) तरीका है?
कोड को दृश्य सी ++ 9 (2008) के तहत संकलित करने योग्य है, इसलिए मैं कुछ भी C++ 11-विशिष्ट का उपयोग नहीं कर सकता।
case a: return &FunctionWrapper<a>::template go<T>;
// ^^^^^^^^
case b: return &FunctionWrapper<b>::template go<T>;
// ^^^^^^^^
इस संकलक क्या एक टेम्पलेट के नाम के रूप में गुंजाइश संकल्प ऑपरेटर (::
) इस प्रकार पार्स करने के लिए कहता है:
आपके उत्तर के लिए धन्यवाद। क्या आपके पास मेरे प्रश्न के दूसरे भाग के बारे में कोई सलाह है? हालांकि यह योजना काम करती है (आपकी मदद के लिए धन्यवाद), मैं इसके साथ वास्तव में खुश नहीं हूं। मैंने एक विकल्प के रूप में आभासी कार्यों का उपयोग करके खोज की, लेकिन मैंने एक ईंट की दीवार मारा जब मुझे एहसास हुआ कि इसके लिए वर्चुअल फ़ंक्शन टेम्पलेट्स की आवश्यकता होगी, जो C++ का समर्थन नहीं करता है। – Spire
@ साम्राज्य: मुझे कबूल करना चाहिए कि मैंने डिजाइन का विश्लेषण करने के लिए समय नहीं लिया और वास्तव में आपका प्रोग्राम क्या करता है, मैंने बस उन दो गलतियों को देखा और सोचा कि मैं एक उत्तर पोस्ट करूंगा। दुर्भाग्यवश मेरे पास अभी अध्ययन करने के लिए समय नहीं है (मेरे पास भी मेरे कार्यक्रमों में मारने के लिए बदसूरत कीड़े हैं;)) –