निम्नलिखित मुद्दा: मैं यह जांचना चाहता हूं कि कोई टेम्प्लेट विधि मौजूद है या नहीं, इसलिए मैंने यहां दिए गए उदाहरणों को अनुकूलित किया है: क्या एक लिखना संभव है किसी फ़ंक्शन के अस्तित्व की जाँच करने के लिए टेम्पलेट?

#include <cstdio>
#include <type_traits>

#define CHECK4_MEMBER_FUNC(RETTYPE,FUNCTION,...) \
template <class ClassType> \
class CIfCheck_##FUNCTION \
{\
private: \
    template <class MemberPointerType> \
    static std::true_type testSignature(RETTYPE (MemberPointerType::*)(__VA_ARGS__)); \
\
    template <class MemberPointerType> \
    static std::false_type testExistence(...); \
   \
    template <class MemberPointerType> \
    static decltype(testSignature(&MemberPointerType::FUNCTION)) testExistence(std::nullptr_t); \
public: \
    using type = decltype(testExistence<ClassType>(nullptr));\
    static const bool value = type::value; \
};


    class Bla
    {
    public:
        template <typename SomeType>
        bool init(SomeType someValue)
        {
            ///
            return true;
        }

        void exec()
        {
            return;
        }
    };

    CHECK4_MEMBER_FUNC(bool, init, int);
    CHECK4_MEMBER_FUNC(void, exec, void);

int main()
{
  Bla blaObj;
  blaObj.init<int>(2);
  static_assert(CIfCheck_exec<Bla>::value, "no exec");
  static_assert(CIfCheck_init<Bla>::value, "no init");

  return 0;
}

लेकिन दुर्भाग्य से static_assert() को init() के लिए ट्रिगर किया गया है (क्योंकि विशेषज्ञता का मूल्यांकन शायद बाद के समय में किया जाता है क्योंकि ऑब्जेक्ट को main() में तत्काल किया जा रहा है)।

मैंने स्पष्ट सदस्य-विशेषज्ञता के साथ प्रयास किया, लेकिन यह अभी भी विफल हो रहा है:

template<>
bool Bla::init<int>(int item)
{
    int temp = item*2; // do with item something
    return false;
}

पीएस .: साइड-प्रश्न (शायद एक और प्रश्न विषय अधिक समझ में आता है:

std::false_type testExistence(...);

मुझे वास्तव में यहाँ एक तर्क क्यों पारित करना है? अगर मैं विविध तर्क ... विकल्प (और nullptr और nullptr_t) को हटा देता हूं, तो testExistence() के अस्पष्ट अस्तित्व के कारण संकलक त्रुटियां।

0
mbed_dev 19 मार्च 2020, 16:31

1 उत्तर

सबसे बढ़िया उत्तर

लेकिन दुर्भाग्य से static_assert को init के लिए ट्रिगर किया गया है (जैसा कि विशेषज्ञता का मूल्यांकन बाद के समय में किया जाता है क्योंकि ऑब्जेक्ट को मुख्य () में तत्काल किया जा रहा है)

बिल्कुल नहीं।

समस्या यह है कि init() एक टेम्प्लेट विधि है, इसलिए जब आप लिखते हैं

decltype(testSignature(&MemberPointerType::FUNCTION))

कोई सूचक नहीं चुना गया है क्योंकि संकलक सही विधि का चयन नहीं कर सकता है।

आप के साथ कोशिश कर सकते हैं

decltype(testSignature(&MemberPointerType::template FUNCTION<__VA_ARGS__>))

लेकिन अब exec() के लिए काम नहीं करता है जो एक टेम्पलेट विधि नहीं है

टेम्पलेट और गैर-टेम्पलेट विधि दोनों के साथ काम करने के लिए ... साधारण पासिंग गर्त एक वैरिएडिक मैक्रो नहीं है क्योंकि वैरिएडिक भाग खाली नहीं हो सकता है ... लेकिन मैं कुछ इस प्रकार प्रस्तावित करता हूं

template <typename...>
struct wrap
 { };

#define CHECK4_MEMBER_FUNC(RETTYPE,FUN,...) \
template <class ClassType> \
class CIfCheck_##FUN \
{\
private: \
    template <typename MPT> \
    static auto testSig (wrap<void>) \
       -> std::is_same<decltype(std::declval<MPT>().FUN()),\
                       RETTYPE>; \
    \
    template <typename MPT, typename ... As> \
    static auto testSig (wrap<As...>) \
       -> std::is_same<decltype(std::declval<MPT>().FUN(std::declval<As>()...)), \
                       RETTYPE>; \
    \
    template <typename...> \
    static std::false_type testSig (...);\
    \
public: \
    using type = decltype(testSig<ClassType>(wrap<__VA_ARGS__>{}));\
    static const bool value = type::value; \
};

ध्यान दें कि मैंने टेम्प्लेट पैरामीटर प्रकारों को लपेटने के लिए एक wrap संरचना जोड़ी है; आमतौर पर std::tuple का उपयोग किया जाता है, लेकिन, इस मामले में, हमें wrap<void> की आवश्यकता होती है क्योंकि std::tuple<void> त्रुटि देता है।

यह भी देखें कि मेरा समाधान दूसरे दृष्टिकोण से अलग है (और आपकी विशिष्ट आवश्यकताओं के अनुसार बेहतर या बदतर हो सकता है): आपका समाधान जांचता है कि क्या बिल्कुल हस्ताक्षर के साथ एक विधि मौजूद है; मेरा समाधान जांचता है कि क्या कोई विधि मौजूद है जो तर्कों की दी गई सूची के साथ कॉल करने योग्य है।

ठोस उदाहरण: मान लीजिए कि एक Bla::foo() विधि है जो एक long मान को स्वीकार करती है

    void foo (long)
     { }

अपने समाधान के साथ, यदि आप int पैरामीटर की जांच करते हैं

CHECK4_MEMBER_FUNC(void, foo, int);

static_assert( false == CIfCheck_foo<Bla>::value, "no foo with int");

आपको CIfCheck_foo से एक false मान मिलता है क्योंकि Bla में foo प्रकार की void(&BLA::*)(int) कोई विधि नहीं है (एक void(&BLA::*)(long) है जो फरक है)।

मेरी विधि से आपको CIFCheck_foo से सत्य मान मिलता है क्योंकि foo(long) एक भी स्वीकार करते हैं int मान (और लौटा हुआ प्रकार void है)।


std::false_type testExistence(...);

मुझे वास्तव में यहाँ एक तर्क क्यों पारित करना है? अगर मैं विविध तर्क ... विकल्प (और nullptr और nullptr_t) को हटा देता हूं, तो testExistence() के अस्पष्ट अस्तित्व के कारण संकलक त्रुटियां।

वह testExistence(), जैसे

    template <typename...> \
    static std::false_type testSig (...);\

दूसरी पसंद है।

मेरा मतलब... जब आप testExistence() को decltype() के अंदर मैक्रो कॉल करते हैं

decltype(testExistence<ClassType>(nullptr));

या मेरी मैक्रो कॉल testSig() अंदर decltype()

decltype(testSig<ClassType>(wrap<__VA_ARGS__>{}));

कॉल जो तर्क के साथ कार्य करता है (nullptr या wrap<__VA_ARGS__>{})।

जब पहली पसंद उपलब्ध हो (जब आपके मामले में एक RETTYPE (MemberPointerType::*)(__VA_ARGS__) मौजूद हो, मेरे उदाहरण में आवश्यक तर्कों के साथ एक विधि कब कॉल करने योग्य है), संकलक उस संस्करण को चुनता है और std::true_type (या std::is_same मेरे कोड में)।

लेकिन जब पहली पसंद उपलब्ध नहीं है?

दूसरा विकल्प, std::false लौटने वाले संस्करणों की आवश्यकता है। लेकिन कॉल एक तर्क के साथ है। यहाँ इलिप्सिस पुरानी सी-स्टाइल वैरिएडिक तर्क सूची है और शून्य या अधिक तर्क स्वीकार करती है, इसलिए एक तर्क भी स्वीकार करें।

यदि आप इलिप्सिस (...) को हटाते हैं, तो दूसरा विकल्प अब एक तर्क को स्वीकार नहीं कर सकता है (शून्य तर्क कार्य बन जाते हैं) और आपको एक संकलन त्रुटि मिलती है क्योंकि संकलक को एक तर्क के साथ संगत दूसरा विकल्प फ़ंक्शन नहीं मिलता है .

1
max66 20 मार्च 2020, 16:40