2017-01-30 20 views
5

यह देखने के लिए एक तरीका बनाने का प्रयास करने की कोशिश कर रहा है कि किसी दिए गए वर्ग में एक दिया गया फ़ंक्शन है जिसे आमंत्रित किया जा सकता है, और कुछ प्रकार देता है।कक्षा के सदस्य फ़ंक्शन

क्या मैं यहां गलत कर रहा हूं पर कोई विचार? क्या यह निर्धारित करने का कोई बेहतर तरीका है कि किसी दिए गए विधि को कक्षा के लिए आमंत्रित किया जा सकता है?

#include <string> 
#include <type_traits> 

#define GENERATE_HAS_MEMBER_FUNC(func, rettype)        \ 
template<typename T, class Enable = void> struct has_##func;     \ 
template<typename T, class U> struct has_##func : std::false_type {};   \ 
template<typename T>               \ 
struct has_##func<T,               \ 
        typename std::enable_if<std::is_same<      \ 
         typename std::result_of<decltype (&T::func)(T)>::type, \ 
         rettype>::value>::type> : std::true_type{};    \ 
template<class T> constexpr bool has_##func##_v = has_##func<T>::value; 

GENERATE_HAS_MEMBER_FUNC(str, std::string) 
GENERATE_HAS_MEMBER_FUNC(str2, std::string) 
GENERATE_HAS_MEMBER_FUNC(funca, std::string) 
GENERATE_HAS_MEMBER_FUNC(strK, std::string) 
GENERATE_HAS_MEMBER_FUNC(fancy, std::string) 
GENERATE_HAS_MEMBER_FUNC(really, std::string) 

struct A1 { 
    virtual std::string str() const { return ""; } 
    std::string strK() const { return ""; } 
    virtual std::string fancy()=0; 
}; 

struct A2 : A1 { 
    std::string str() const override { return ""; } 
    std::string funca(); 
    std::string fancy() override { return ""; } 
    std::string really(int a=0) const { return std::to_string(a); } 

}; 

int main() { 
    static_assert(has_str_v<A1>, 
     "A1::str is virtual method with impl on base"); // MSVC: NO, clang: OK, GCC: NO 
    static_assert(has_strK_v<A1>, 
     "A1::strK is implemented inline "); // MSVC: NO, clang: OK, GCC: NO 
    static_assert(has_fancy_v<A1>, 
     "A1::fancy is a pure virtual method on base"); // MSVC: NO, clang: OK, GCC: NO 
    static_assert(!has_really_v<A1>, 
     "A1::really doesn't exist in A1"); // MSVC: OK, clang: OK, GCC: OK 

    static_assert(has_str_v<A2>, 
     "A2::str is override method "); // MSVC: OK, clang: OK, GCC: OK 
    static_assert(!has_str2_v<A2>, 
     "A2::str2 does not exist in A2"); // MSVC: NO, clang: OK, GCC: OK 
    static_assert(has_funca_v<A2>, 
     "A2::funca is defined (no impl) in A2"); // MSVC: OK, clang: OK, GCC: OK 
    static_assert(has_strK_v<A2>, 
     "A2::strK is implemented method on base"); // MSVC: OK, clang: OK, GCC: OK 
    static_assert(has_fancy_v<A2>, 
     "A1::fancy is a override of pure virtual method of base"); // MSVC: OK, clang: OK, GCC: OK 
    static_assert(has_really_v<A2>, 
     "A2::really has default param (can be invoked without params)"); // MSVC: OK, clang: NO, GCC: NO 
    return 0; 
} 

इस कार्यान्वयन पर कुछ आश्चर्य।

संपादित करें: लागू करने के लिए @ Jarod42 और @Vittorio रोमियो भयानक सुझावों को आज़माने पर:, static_assert (has_really_v:

#define GENERATE_HAS_MEMBER_FUNC(func, rettype)        \ 
template<class T> using _has_##func_chk =          \ 
     decltype(std::declval<T &>().func());         \ 
template<class T> constexpr bool has_##func##_v =        \ 
     is_detected_exact_v<rettype, _has_##func_chk, T>; 

अब दो टेस्ट केस अभी भी VS2015 पर असफल (किसी भी मतलब नहीं है) "ए 1 :: वास्तव में ए 1 में मौजूद नहीं है"); static_assert (! Has_str2_v, "ए 2 :: str2 ए 2 में मौजूद नहीं है");

शायद कुछ मूर्खतापूर्ण चीज है जो मुझे याद आ रही है ... कोई सुराग?

+1

क्या आपने 'std :: is_detected' (सी ++ 17 लेकिन सी ++ 11 में लागू करने योग्य) को देखा है? – Jarod42

उत्तर

9

क्या यह निर्धारित करने का एक बेहतर तरीका है कि किसी दिए गए विधि को कक्षा के लिए आमंत्रित किया जा सकता है या नहीं?

हाँ, आप उपयोग कर सकते हैं detection idiom, जो सी ++ 11 में लागू किया जा सकता (लिंक किए गए पेज एक वैध कार्यान्वयन शामिल हैं)।

यहां एक उदाहरण है: Cat में float Cat::purr(int) विधि है?

struct Cat { float purr(int){} }; 

template<class T> 
using has_purr = 
    decltype(std::declval<T&>().purr(std::declval<int>())); 

static_assert(std::experimental::is_detected_exact_v<float, has_purr, Cat>); 

wandbox example


आवश्यक का पता लगाने मुहावरा सी ++ 17 निर्भरता सी ++ 11 में लागू करने के लिए तुच्छ हैं:

template<class...> 
using void_t = void; 

struct nonesuch { 
    nonesuch() = delete; 
    ~nonesuch() = delete; 
    nonesuch(nonesuch const&) = delete; 
    void operator=(nonesuch const&) = delete; 
}; 

यहाँ एक fully C++11-compliant minimal example on wandbox है।

+0

@AndyG: मेरा जवाब अपडेट किया गया। –

+0

बहुत बहुत धन्यवाद। मैं एमएसवीसी में लागू करने की कोशिश कर रहा हूं और एक ही परीक्षण चला रहा हूं। लेकिन आपके वंडबॉक्स कोड में परिदृश्यों को त्वरित परीक्षण करने के लिए कुछ छोटे बदलाव करना, ऐसा लगता है कि यह वास्तव में सबसे अच्छा तरीका है, – nCoder

+0

कंपाइलर्स में अधिक लगातार परिणाम, लेकिन कुछ परीक्षण विफल हो रहे हैं ... मेरी बग कितनी मूर्खतापूर्ण है? (इसे नहीं देख सकता): पी – nCoder

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