2017-07-15 30 views
5

मैं is_callable संरचना परिभाषित उपयोग कर रहा हूँ के रूप मेंचेक अगर एक समारोह प्रतिदेय है

template <typename F, typename... Args> 
struct is_callable { 
    template <typename U> 
    static auto test(U* p) -> decltype((*p)(std::declval<Args>()...), void(), std::true_type()); 

    template <typename U> 
    static auto test(...) -> decltype(std::false_type()); 

    static constexpr bool value = decltype(test<F>(nullptr))::value; 
}; 

मैं इस का उपयोग कर रहा एक लैम्ब्डा परीक्षण करने के लिए के रूप में घोषित इस प्रकार है:

template <typename T> 
struct runner { 
    T t; 

    template <typename F, typename = typename std::enable_if<is_callable<F, T&>::value || is_callable<F, T&&>::value>::type> 
    void run(F&& f) { 
    return f(t); 
    } 
}; 

runner<int> a{0}; 
a.run([&] (auto& x) { 
    x++; 
}); 

क्यों इस पर संकलन विफल करता है AppleClang पर enable_if? auto एस सही ढंग से नहीं लेना चाहिए?

+0

[मेरे लिए काम करता है] (http://coliru.stacked-crooked.com/a/b83c21fddc4e15cb)। आपका 'क्लैंग' संस्करण क्या है और विशिष्ट त्रुटि संदेश क्या है? – Rakete1111

+0

@ Rakete1111 'उम्मीदवार टेम्पलेट पर ध्यान नहीं दिया: द्वारा 'enable_if'' अक्षम एप्पल LLVM संस्करण 8.1.0 (बजना-802.0.42) – subzero

+0

तुम क्यों की जाँच कर रहे हैं अगर यह' टी एंड '* या *' टी के साथ प्रतिदेय है && '? आप इसे 'टी एंड' के साथ बुला रहे हैं, बस इसे जांचें। – Barry

उत्तर

1

true_typetest के लिए आपका मामला गलत लग रहा है। किसी भी दर पर, आपका कोड जितना जटिल होना चाहिए उससे कहीं अधिक जटिल है। निम्नलिखित न्यूनतम काम कर उदाहरण का प्रयास करें:

#include <utility> 

template<typename F, typename...Args> struct is_callable { 
    template<typename F2, typename...Args2> static constexpr std::true_type 
    test(decltype(std::declval<F2>()(std::declval<Args2>()...)) *) { return {}; } 

    template<typename F2, typename...Args2> static constexpr std::false_type 
    test(...) { return {}; } 

    static constexpr bool value = decltype(test<F, Args...>(nullptr))::value; 
}; 

void f0(); 
static_assert(is_callable<decltype(f0)>::value, "f0()"); 
static_assert(!is_callable<decltype(f0), int>::value, "f0(0)"); 

int f1(int); 
static_assert(!is_callable<decltype(f1)>::value, "f1()"); 
static_assert(is_callable<decltype(f1), int>::value, "f1(0)"); 
static_assert(!is_callable<decltype(f1), int, int>::value, "f1(0, 0)"); 

auto __attribute__((unused)) f2 = [](int, char *) { return 7; }; 
static_assert(is_callable<decltype(f2), int, char *>::value, "f2(int, char *)"); 
static_assert(!is_callable<decltype(f2), int, int>::value, "f2(int, int)"); 
+1

यह एक * भयानक * 'is_callable' है। –

+0

क्या भयानक है? यह सी ++ 11, 14, और 17 के साथ काम करता है, और बहुत स्पष्ट रूप से और स्पष्ट रूप से SFINAE का उपयोग करता है। – user3188445

0

समस्या is_callable परीक्षण वर्ग नहीं है, लेकिन इसके बारे में अपने उपयोग।

जब एक समारोह के टेम्पलेट तर्क सूची में std::enable_if का उपयोग कर, आप इसे इस तरह से उपयोग करने के लिए:

template <typename T> 
struct runner { 
    T t; 

    template 
    < 
    typename F, 
    std::enable_if_t<is_callable<std::decay_t<F>, T&>::value || is_callable<F, T&&>::value>* = nullptr 
    > 
    void run(F&& f) { 
    return f(t); 
    } 
}; 

प्रपत्र आप का उपयोग करने की कोशिश की पीछे वापसी प्रकार के रूप में उपयोग के लिए है:

template<typename F> 
    auto run(F&& f) 
    -> std::enable_if_t<is_callable<std::decay_t<F>, T&>::value || is_callable<F, T&&>::value> 
    { 
    return f(t); 
    } 

is_callable प्रकार सही है। ऐसा लगता है कि मैंने पहले ओवरफ्लो ढेर करने के लिए पोस्ट किया है।

+1

आपको ऐसा क्यों लगता है कि आपको इसका उपयोग करने के लिए * है *? – Barry

+0

@ बैरी क्योंकि यह फ़ंक्शन सक्षम करने के लिए 3 सही तरीकों में से एक है: टाइप * = nullptr, पिछला प्रकार या झूठी तर्क। –

+0

मुझे यकीन नहीं है कि ऐसा क्यों लगता है कि यह मामला है। 'टेम्पलेट <..., typename = std :: enable_if_t <...>>' काफी सामान्य रूप से उपयोग किया जाता है। – Barry

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