2017-08-04 20 views
6

मान लीजिए के साथ संयुक्त टेम्पलेट मैं मैं कॉलबैक प्रकार specificy जबकि अभी भी variadic टेम्पलेट तर्क है करने के लिए जा रहा है ablet वैकल्पिक करने में सक्षम होना चाहते हैं एक वर्गvariadic डिफ़ॉल्ट टेम्पलेट तर्क

enum CallbackType 
{ 
    SYNC, 
    ASYNC 
} 


template<CallbackType CB = SYNC, typename... Args> 
class Callback 
{ 
} 

है। अब मैं समझता हूं कि संकलक उन्हें अलग नहीं बता सकता है, लेकिन शायद विशिष्ट मामले को संभालने का कोई तरीका है जहां पहला टेम्पलेट तर्क CallbackType का है?

Callback<int int> //Should be Callback<SYNC, int, int> 
Callback<ASYNC, int, int> //Should be Callback<ASYNC, int, int> 

उत्तर

7

, सी ++ के दो पहलू हैं, जब यह variadic टेम्पलेट्स, कि आपके मामले में एक दूसरे के साथ संघर्ष में हैं करने के लिए आता है:

  1. चूक टेम्प्लेट पैरामीटर गैर डिफॉल्ट टेम्पलेट मापदंडों पूर्व में होना नहीं होना चाहिए ।

  2. variadic टेम्प्लेट पैरामीटर गैर variadic टेम्प्लेट पैरामीटर पूर्व में होना नहीं होना चाहिए।

यह कई स्थितियों में निश्चित रूप से संभव है, सही ढंग से घोषित करने के लिए, और उपयोग करते हैं, टेम्पलेट्स जिसका मापदंडों इन नियमों का पालन नहीं करते, लेकिन उन स्थितियों को इस सवाल के प्रयोजन के लिए महत्वपूर्ण नहीं हैं। आपके मामले में, यह नीचे आता है कि आपके दोनों टेम्पलेट पैरामीटर अपने स्वयं के व्यक्तिगत कारणों से अपने टेम्पलेट में अंतिम पैरामीटर बनना चाहते हैं। संक्षेप में यह समस्या है।

template<CallbackType CB = ASYNC> 
class CallbackClass { 

public: 

    template<typename... Args> class Callback 
    { 
    } 
}; 

फिर, अपने दो उदाहरण बन:

CallbackClass<>::Callback<int, int> 

और

CallbackClass<ASYNC>::Callback<int, int> 

आप करेंगे

इस विरोध को हल करने के लिए सबसे आसान तरीका है एक आंतरिक टेम्पलेट का उपयोग करने के लिए है निश्चित रूप से लंबे वर्ग के नाम के साथ खत्म करो। लेकिन यह typedef और using है। उदाहरण के लिए:

template<typename ...Args> 
using DefaultCallback=CallbackClass<>::Callback<Args...>; 

तो का उपयोग

DefaultCallback<int, int> 
+0

बहुत बुरा हम अच्छी चीजें नहीं कर सकते :(, मैं हमेशा कॉलमटाइप को enum टेम्पलेट तर्क के रूप में लेना चाहता हूं और बाकी को विविधता के रूप में लेना चाहता हूं, लेकिन मुझे लगता है कि यह चीजों को अलग नहीं बताता है। –

2

आपने एक सिंटैक्स बहुत metaprogramming का एक सा के साथ अपने मूल वाक्य रचना के करीब हो सकता है। आप को परिभाषित है कि आपके द्वारा CallbackType और एक CallbackImpl:

enum CallbackType 
{ 
    SYNC, 
    ASYNC, 
}; 

template<CallbackType CB, typename... Args> 
class CallbackImpl 
{ 
}; 

तो कुछ बातें "डिफ़ॉल्ट तर्क" पाने के लिए क्या: फिर

// We need to treat the CallbackType argument as a type, not as a value. 
// Thus, we need to wrap it in a type. 
template <CallbackType cb> 
using CallbackT = std::integral_constant<CallbackType, cb>; 

// We need to be able to detect if the first type passed in is this CallbackT 
template <typename T> 
struct is_callback_type 
    : std::false_type 
{}; 

template <CallbackType cb> 
struct is_callback_type<CallbackT<cb>> 
    : std::true_type 
{}; 

template <typename T> 
using is_callback_type_t = typename is_callback_type<T>::type; 

// Here we do the work. This is the base case, where the first arg 
// is not a CallbackT. Note that this works for an empty Args as well 
template <typename AlwaysVoid, typename... Args> 
struct construct_callback_impl 
{ 
    using type = CallbackImpl<SYNC, Args...>; 
}; 

// If the Args list is of at least size 1, 
template <typename CallbackType, typename... Args> 
struct construct_callback_impl< 
    // Use this specialization only if the first type is our CallbackT 
    typename std::enable_if<is_callback_type_t<CallbackType>::value>::type, 
    CallbackType, 
    Args...> 
{ 
    // Forward the specified CallbackType on to the CallbackImpl 
    using type = CallbackImpl<CallbackType::value, Args...>; 
}; 

// Wrap this utility into a nicer calling syntax  
template <typename... Args> 
using Callback = typename construct_callback_impl<void, Args...>::type; 

, इसका इस्तेमाल किया जा सकता है:

Callback<int, int>     // type is CallbackImpl<SYNC, int, int> 
Callback<CallbackT<SYNC>, int, int> // type is CallbackImpl<SYNC, int, int> 
Callback<CallbackT<ASYNC>, int, int> // type is CallbackImpl<ASYNC, int, int> 
Callback<>       // type is CallbackImpl<SYNC> 

Live on Godbolt

मुझे लगता है कि यह स्पष्ट है कि यह आमतौर पर क्यों नहीं किया जाता है।

संबंधित मुद्दे