2015-10-27 4 views
10

मैं के लिए परीक्षण करने के लिए SFINAE भाव का इस्तेमाल किया है एक प्रकार का समर्थन करता है, तो operator<<क्या किसी प्रकार के "प्रयोजन के लिए" का एक SFINAE परीक्षण लिखने का कोई तरीका है?

namespace details 
{ 
    template<typename T> 
    struct sfinae_true : std::true_type 
    { 
    }; 

    template<typename T> 
    sfinae_true<decltype (std::declval<std::ostream &>() << std::declval<T const &>())> test_for_ostream (int); 

    template<typename T> 
    std::false_type test_for_ostream (long); 
} 

template<typename T> 
struct supports_ostream : decltype (details::test_for_ostream<T> (0)) 
{ 
}; 

क्या मैं परीक्षण करना चाहते हैं है अगर यह एक प्रकार T इस

for (auto && v : vs) {} // vs is T const & 

दुविधा है की तरह अधिक दोहराया जा सकता है यह एक बयान है और एक अभिव्यक्ति नहीं है जो इसे decltype

के साथ उपयोग करने में असंगत बनाता है, मैं एक बयान को अभिव्यक्त करने के लिए लैम्बडा का उपयोग करने के बारे में सोच रहा था इस

auto x = []() { for (auto && v : vs) {}; return 0; }(); // vs is T const & 

हालांकि lambdas युक्त अभिव्यक्ति की decltype स्पष्ट रूप से मना किया जा रहा है आयन की तरह:

namespace details 
{ 
    template<typename T> 
    sfinae_true<decltype (
    []() { for (auto && v : std::declval<T const &>()) ; }() 
    )> test_for_container (int); 
    // Won't work because lambdas aren't allowed in unevaluated contexts 

    template<typename T> 
    std::false_type test_for_container (long); 
} 

template<typename T> 
struct is_container : decltype (details::test_for_container<T> (0)) 
{ 
}; 

तो:

// Won't compile in clang, gcc nor VC++ 
using x_t = decltype ([]() { for (auto && v : vs) {}; return 0; }()); // vs is T const & 

तो है कि इस तरह के एक परीक्षण समारोह में उपयोग के लिए यह अयोग्य सिद्ध होने मैंने विचारों से बाहर भाग लिया है, इसलिए मैंने सोचा कि शायद कोई @Stackoverflow कुछ दिलचस्प के साथ आ सकता है।

पीएस।

मैं कुछ हद तक समझ सकता हूं कि क्यों decltype ([]() {}) की अनुमति नहीं है लेकिन decltype ([]() {}()) हमेशा अच्छी तरह परिभाषित यानी void होना चाहिए।

+1

Fwiw, मेरा उत्तर [यहां] (https://stackoverflow.com/प्रश्न/32293860/सिमुलेटिंग-द-रेंज-आधारित-लूप्स-स्टार्ट-एंड-व्यवहार) SFINAE अनुकूल है, यानी कॉल वैधता की जांच करना काम करेगा। – Columbo

+0

हाय, धन्यवाद। इससे काम बन जाएगा। उस पर मेरा खुद का स्टैब कुछ हद तक समान दिखता था लेकिन कुछ मामलों को याद करता था। – FuleSnabel

उत्तर

5

मामलों के बहुमत निम्नलिखित विशेषता पर्याप्त होना चाहिए के लिए:

#include <type_traits> 
#include <utility> 
#include <iterator> 

namespace detail 
{ 
    using std::begin; 
    using std::end; 

    template <typename T> 
    auto is_range_based_iterable(...) 
     -> std::false_type; 

    template <typename T 
      , typename I = typename std::decay<decltype(std::declval<T>().begin())>::type> 
    auto is_range_based_iterable(int) 
     -> decltype(std::declval<T>().begin() 
        , std::declval<T>().end() 
        , ++std::declval<I&>() 
        , void() 
        , std::integral_constant<bool, 
         std::is_convertible<decltype(std::declval<I&>() != std::declval<I&>()), bool>::value 
        && !std::is_void<decltype(*std::declval<I&>())>::value 
        && std::is_copy_constructible<I>::value 
        >{}); 

    template <typename T 
      , typename I = typename std::decay<decltype(begin(std::declval<T>()))>::type> 
    auto is_range_based_iterable(char) 
     -> decltype(begin(std::declval<T>()) 
        , end(std::declval<T>()) 
        , ++std::declval<I&>() 
        , void() 
        , std::integral_constant<bool, 
         std::is_convertible<decltype(std::declval<I&>() != std::declval<I&>()), bool>::value 
        && !std::is_void<decltype(*std::declval<I&>())>::value 
        && std::is_copy_constructible<I>::value 
        >{}); 
} 

template <typename T> 
struct is_range_based_iterable : decltype(detail::is_range_based_iterable<T>(0)) {}; 

टेस्ट:

#include <vector> 
#include <array> 

int main() 
{ 
    static_assert(is_range_based_iterable<std::vector<int>>::value, "!"); 
    static_assert(is_range_based_iterable<std::array<int, 5>>::value, "!"); 
    static_assert(is_range_based_iterable<int(&)[5]>::value, "!"); 
} 

DEMO

+2

आपको '.begin()' /'.end() 'सदस्यों के लिए परीक्षण करने की आवश्यकता नहीं है,' std' संस्करणों के साथ 'start()'/'end()' के एडीएल-जागरूक लुकअप के दायरे में आपके लिए अच्छी तरह से संभालती है। –

+0

हाय। यह सवालों का जवाब देता है। मुझे लगता है कि मैं गुप्त रूप से इसके लिए परीक्षण करने के लिए 'कथन' का उपयोग करने के लिए गुप्त रूप से काम करना चाहता था। – FuleSnabel

+1

@ ल्यूकडैंटन नंबर। मैं खुद को [एक कंटेनर] (http://coliru.stacked-crooked.com/a/2a13665c7c84235d) कल्पना कर सकता हूं जो सदस्य कार्यों 'प्रारंभ() '/' end() 'के माध्यम से पुनरावर्तनीय है, और जिसका नेमस्पेस 'प्रारंभ()' और 'अंत()' को परिभाषित करता है, जो एडीएल के माध्यम से मिलता है, आपको कंटेनर के तत्वों की गणना करने नहीं देगा –

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

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