मैं अपनी कक्षा का उपयोग अपने मूल वर्ग में से किसी एक के टेम्पलेट पैरामीटर के रूप में कर रहा हूं, और यह कि अभिभावक वर्ग इसे टेम्पलेट तर्क में उपयोग करता है (हालांकि आकार())।आधार वर्ग के टेम्पलेट पैरामीटर के रूप में बाल वर्ग का उपयोग करना और घोंसला वाले नाम के रूप में
और संकलक मुझे देता है:
त्रुटि: अधूरा प्रकार 'Invoker :: workerClass {उर्फ MyClass}' नेस्टेड नाम विनिर्देशक में इस्तेमाल
फिर भी वर्ग अच्छी तरह से फाइल में परिभाषित किया गया है । मुझे लगता है कि ऐसा इसलिए है क्योंकि बेस क्लास 'तत्कालता के पल में बाल वर्ग को तत्काल नहीं किया जाता है, फिर भी इस तरह की चीज CRTP के साथ होती है और इसमें कोई समस्या नहीं है।
टेम्पलेट तर्क में बाल वर्ग का उपयोग करने का कारण एक अलग फ़ंक्शन कॉल करना है यदि बच्चे वर्ग के पास एक विशिष्ट कार्य है, या नहीं है।
यहाँ के परीक्षण के लिए एक न्यूनतम कोड है
/* Structure similar to boost's enable if, to use
SFINAE */
template <int X=0, class U = void>
struct test {
typedef U type;
};
enum Commands {
Swim,
Fly
};
/* Structure used for template overloading,
as no partial function template specialization available */
template<Commands T>
struct Param {
};
template <class T>
class Invoker
{
public:
typedef T workerClass;
workerClass *wc() {
return static_cast<workerClass*>(this);
}
template <Commands command>
void invoke() {
invoke2(Param<command>());
}
/* If the child class has those functions, call them */
/* Needs template paramter Y to apply SFINAE */
template<class Y=int>
typename test<sizeof(Y)+sizeof(decltype(&workerClass::fly))>::type
invoke2(Param<Fly>) {
wc()->fly();
}
template<class Y=int>
typename test<sizeof(Y)+sizeof(decltype(&workerClass::swim))>::type
invoke2(Param<Swim>) {
wc()->shoot();
}
template<Commands command>
void invoke2(Param<command>) {
/* Default action */
printf("Default handler for command %d\n", command);
}
};
template <class T, class Inv = Invoker<T> >
class BaseClass : public Inv
{
public:
template<Commands command>
void invoke() {
Inv::template invoke<command>();
}
};
class MyClass : public BaseClass<MyClass>
{
public:
void swim() {
printf("Swimming like a fish!\n");
}
/* void fly(); */
};
void testing() {
MyClass foo;
foo.invoke<Fly>(); /* No 'void fly()' in MyClass, calls the default handler */
foo.invoke<Swim>(); /* Should print the swimming message */
}
त्रुटि पंक्ति होता है:
typename test<sizeof(Y)+sizeof(decltype(&workerClass::fly))>::type
तो, वहाँ किसी भी संकलक है कि इस का समर्थन करता है, या इस पर स्पष्ट रूप के रूप में मानक द्वारा निर्दिष्ट किया जाता टेम्पलेट्स का अमान्य उपयोग? क्या मुझे ऐसा करने के तरीके को बदलना है और चारों ओर एक रास्ता खोजना है? सीआरटीपी मुझे आशा दे रहा है कि कोड वैध हो सकता है, लेकिन मुझे यकीन नहीं है।
यदि यह वास्तव में संभव नहीं है, तो क्यों, और सीआरटीपी क्यों काम करता है?
ठीक है, समस्या स्पष्ट है कम से कम: आप एक आत्म निर्देशात्मक पुनरावर्ती परिभाषा कर रहे हैं: 'BaseClass' आवश्यकता पूरा '' MyClass' decltype की वजह से 'अभिव्यक्ति, लेकिन' MyClass' को बेस क्लास के रूप में एक पूर्ण 'बेस क्लास ' की आवश्यकता है। –
आपको संकेत की एक अतिरिक्त परत के पीछे विशेषज्ञता को छिपाने की जरूरत है ताकि बेस बेस परिभाषा के हिस्से के रूप में उनका मूल्यांकन नहीं किया जा सके। उन्हें एक निजी नेस्टेड प्रकार में रखें और सभी ठीक काम करेंगे। – ildjarn
सीआरटीपी इस कारण से मुश्किल है, आप जिस समस्या का सामना कर रहे हैं वह समझने में आसान है: आधार टेम्पलेट को कक्षा घोषणा के हिस्से के रूप में तत्काल किया जाता है, एक बिंदु पर जहां यह अभी तक पूरा नहीं हुआ है (लगता है कि यह प्रकार अभी भी इस बात पर निर्भर करता है कि आधार टेम्पलेट जोड़ सकता है, इसलिए कोई तरीका नहीं है कि संकलक यह जान सके कि व्युत्पन्न प्रकार पहले बेस टेम्पलेट को संसाधित किए बिना कैसा होगा - आधार यह है कि आधार सदस्य गुणों को जोड़ सकता है जो आकार बदलते हैं, या आभासी सदस्य फ़ंक्शन जो बदल सकते हैं व्युत्पन्न प्रकार में फ़ंक्शन घोषणाओं का अर्थ) –