2017-12-11 60 views
5

चलो कहते हैं कि मैं इस तरह एक टेम्पलेट वर्ग करते हैं:चेक अगर एक विधि का एक टेम्पलेट विशेषज्ञता मौजूद है

template<typename TRequest, typename TResponse = void> 
class handler 
{ 
private: 
    static void validate_core(const TRequest& request); 
    static TResponse process_core(const TRequest& request); 
public: 
    static TResponse process(const TRequest& request) 
    { 
     if (validate_core is implemented) 
     { 
      log("begin validate"); 
      validate_core(request); 
     } 

     return process_core(request); 
    } 
}; 

process_core अलग TRequest/TResponse प्रकार के लिए लागू किया जाना है, जबकि validate_core वैकल्पिक है, मैं आह्वान करने के लिए चाहते हैं अगर यह लागू किया गया है।

वर्तमान में मेरा कामकाज validate_core पर डिफ़ॉल्ट खाली कार्यान्वयन दे रहा है, यदि यह विशिष्ट नहीं है तो खाली विधि लागू की जाती है। मैं जानना चाहता हूं कि कोई बेहतर तरीका है या नहीं।

+1

की (https://stackoverflow.com [एक प्रकार एक विशिष्ट हस्ताक्षर के साथ एक निर्माता है कि क्या यह निर्धारित करने के पता लगाने मुहावरा का प्रयोग] संभावित डुप्लिकेट: (नोटा लाभ मैं बदलाव कर दिया है समारोह हस्ताक्षर इस कोड compilable बनाने के लिए)/प्रश्न/35669304/उपयोग-द-डिटेक्शन-मुहावरे-से-निर्धारण-चाहे-एक-प्रकार-एक-कन्स्ट्रक्टर-साथ-साथ) –

+0

लिंक किए गए डुप्ले कभी भी थोड़ा अलग हैं, जैसा कि पहचान मुहावरे के मामले में है , लेकिन आप इसे काम करने में सक्षम होना चाहिए। –

+0

@PasserBy सामान्य तरीकों के लिए मैंने कुछ समाधान देखा, हालांकि वे टेम्पलेट विधियों के लिए उपयुक्त नहीं हैं। –

उत्तर

-1

वर्तमान में मेरा कामकाज validate_core पर डिफ़ॉल्ट खाली कार्यान्वयन दे रहा है, यदि यह विशिष्ट नहीं है तो एक खाली विधि लागू की जाती है। मैं जानना चाहता हूं कि कोई बेहतर तरीका है या नहीं।

यह मुझे एक बहुत अच्छा तरीका लगता है।

नहीं

अपनी आवश्यकताओं को समझने के लिए यकीन है कि लेकिन मैं आपको handler के शरीर के भीतर validate_core()

के टेम्पलेट संस्करण को हटाना और सक्षम हो सकता है, मान लीजिए एक या अधिक गैर टेम्पलेट विशेषज्ञताओं

static void validate_core (int const &) 
    { /* do something */ } 

    static void validate_core (long const &) 
    { /* do something */ } 

    // ... 

अगला आप handler के शरीर में जोड़ सकते हैं, यह पता लगाने के लिए एक प्रकार का गुण है कि यह validate_core()

के लिए विशेषज्ञता उपलब्ध है या नहीं
template <typename, typename = void> 
    struct withValidateCore : public std::false_type 
    { }; 

    template <typename T> 
    struct withValidateCore<T, decltype(validate_core(std::declval<T>()))> 
    : public std::true_type 
    { }; 

आप सी ++ 17 इस्तेमाल कर सकते हैं, तो इस तरह से है क्योंकि यह उपलब्ध if constexpr() है दिलचस्प हो सकता है, तो के रूप में संभव कुछ किया जाना चाहिए [खेद: परीक्षण नहीं]

static TResponse process (TRequest const & request) 
{ 
    if constexpr (withValidateCore<TRequest>::value) 
    { 
     log("begin validate"); 
     validate_core(request); 
    } 

    return process_core(request); 
} 

लेकिन तुम सी में चिह्नित ++ 14, इसलिए if constexpr() उपलब्ध नहीं है और withValidateCore का उपयोग करने के लिए सबसे अच्छा तरीका process() के दो अलग-अलग (SFINAE सक्षम/अक्षम) संस्करणों को लागू करता है;

template <typename TRq = TRequest> 
    static std::enable_if_t<(true == withValidateCore<TRq>{}) 
     && (true == std::is_same<TRq, TRequest>{}), TResponse> 
    process (TRequest const & request) 
    { 
    validate_core(request); 

    return process_core(request); 
    } 

    template <typename TRq = TRequest> 
    static std::enable_if_t<(false == withValidateCore<TRq>{}) 
     && (true == std::is_same<TRq, TRequest>{}), TResponse> 
    process (TRequest const & request) 
    { return process_core(request); } 

अन्यथा की तरह कुछ (शायद थोड़ा बेहतर) कुछ validate_core() के एक खाली जेनेरिक संस्करण के आधार पर समाधान (सी ++ 14 में) आधारित टैग भेजने

private: 
    static TResponse process (TRequest const & request, 
          std::true_type const &) 
    { 
     validate_core(request); 

     return process_core(request); 
    } 

    static TResponse process (TRequest const & request, 
          std::false_type const &) 
    { return process_core(request); } 

public: 
    static TResponse process (TRequest const & request) 
    { return process(request, withValidateCore<TRequest>{}); } 

IMHO यह बेहतर है।

वैसे भी, निम्नलिखित एक पूर्ण काम कर उदाहरण

#include <iostream> 
#include <type_traits> 

template <typename TRequest, typename TResponse = void> 
class handler 
{ 
    private: 
     template <typename TRq = TRequest> 
     static void validate_core (TRequest const &) = delete; 

     static void validate_core (int const &) 
     { std::cout << "- validate_core() int case" << std::endl; } 

     static void validate_core (long const &) 
     { std::cout << "- validate_core() long case" << std::endl; } 

     static TResponse process_core (const TRequest &) 
     { return TResponse(); } 

     template <typename, typename = void> 
     struct withValidateCore : public std::false_type 
     { }; 

     template <typename T> 
     struct withValidateCore<T, decltype(validate_core(std::declval<T>()))> 
     : public std::true_type 
     { }; 

    public: 
     template <typename TRq = TRequest> 
     static std::enable_if_t<(true == withValidateCore<TRq>{}) 
      && (true == std::is_same<TRq, TRequest>{}), TResponse> 
     process (TRequest const & request) 
     { 
     validate_core(request); 

     return process_core(request); 
     } 

     template <typename TRq = TRequest> 
     static std::enable_if_t<(false == withValidateCore<TRq>{}) 
      && (true == std::is_same<TRq, TRequest>{}), TResponse> 
     process (TRequest const & request) 
     { return process_core(request); } 
}; 

int main() 
{ 
    handler<int>::process(0);  // print - validate_core() int case 
    handler<int, long>::process(0); // print - validate_core() int case 
    handler<long>::process(0);  // print - validate_core() long case 
    handler<char>::process(0);  // no print 
} 
0

यह संकलन समय पर जांच करने के लिए करता है, तो एक टेम्पलेट विशेषज्ञता कार्यान्वित किया जाता है संभव नहीं है। सबसे अच्छा आप घोषणा और बाहरी टेम्पलेट त्वरण द्वारा एक लिंक-टाइम त्रुटि उत्पन्न कर सकते हैं।

मुझे समझ गया है कि आप चाहते हैं कि process तथाकथित टेम्पलेट विधि डिजाइन पैटर्न लागू करता है। यदि ऐसा है, तो आप सीआरटीपी दिलचस्प के नीचे उपयोग का उपयोग कर सकते हैं।

template<class Derived, typename TRequest, typename TResponse> 
class handler_base 
{ 
private: 
//caution trickery 
static constexpr bool validate_core=false; 

public: 
static TResponse* process(const TRequest& request) 
    { 
    if constexpr (Derived::validate_core) 
    { 
     //log("begin validate"); 
     Derived::validate_core(request); 
    } 

    return Derived::process_core(request); 
    } 
}; 

template<typename TRequest, typename TResponse=void> 
class handler; 

class Req1; 
class Req2; 
class Resp1; 
class Resp2; 

template<> 
class handler<Req1,Resp1> 
    : handler_base<handler<Req1,Resp1>,Req1,Resp1> 
    { 
    static void validate_core(const Req1& request); 
    static Resp1* process_core(const Req1& request); 
    friend handler_base; 
    }; 

template<> 
class handler<Req2,Resp2> 
    : handler_base<handler<Req2,Resp2>,Req2,Resp2> 
    { 
    friend handler_base; 
    static Resp2* process_core(const Req2& request); 
    }; 
//just to force compilation 
template Resp2* handler_base<handler<Req2,Resp2>,Req2,Resp2>::process(const Req2&); 
template Resp1* handler_base<handler<Req1,Resp1>,Req1,Resp1>::process(const Req1&); 
संबंधित मुद्दे