2016-11-18 9 views
9

एक ऐसी अवधारणा कैसे लिखें जो लैंड के लिए रेंज-आधारित प्रकारों का वर्णन करेगी?एक साधारण रेंज अवधारणा कैसे लिखें?

ही एक प्रयास है:

template < typename Range > concept bool RRange 
    = requires(Range range) {{std::begin(range),std::end(range)};}; 

लेकिन क्या मैं वास्तव में चाहते हैं इस तरह की कुछ बात है:

template < typename Range > concept bool RRange 
    = requires(Range range) {{for(auto&& item : range);};}; // compile error 

है कि, RRange सभी प्रकार की अवधारणा अभिव्यक्ति for(auto&& item : range); के लिए मान्य है होना करने के लिए । इस लक्ष्य को हासिल करने का सबसे अच्छा तरीका क्या है?

मैं g++ -std=c++1z -fconcepts के साथ जीसीसी 7 स्नैपशॉट का उपयोग कर रहा हूं।

उत्तर

1

[stmt.ranged] की समीक्षा करते समय मैं यहां आया था।

#include <utility> 
#include <experimental/type_traits> 

template <class T> using begin_non_mf_t = decltype(begin(std::declval<T>())); 
template <class T> using begin_mf_t  = decltype(std::declval<T>().begin()); 
template <class T> using begin_t  = decltype(T::begin); 
template <class T> using end_non_mf_t = decltype(end(std::declval<T>())); 
template <class T> using end_mf_t  = decltype(std::declval<T>().end()); 
template <class T> using end_t   = decltype(T::end); 

template <class T> 
constexpr bool has_member_begin_or_end { 
    std::experimental::is_detected_v<begin_mf_t,T> || 
    std::experimental::is_detected_v<begin_t,T> || 
    std::experimental::is_detected_v<end_mf_t,T> || 
    std::experimental::is_detected_v<end_t,T>}; 

template <class T> 
std::add_lvalue_reference_t<T> declref() noexcept; 
template <class T> using declref_t = decltype(declref<T>()); 

template <class T> 
concept bool Range = 
    requires /*Arrays*/ { 
     requires std::is_array_v<T>; 
     requires std::extent_v<T>!=0; // Extent is known. 
    } || 
    /*Classes with member begin/end*/ 
    requires { 
     requires std::is_class_v<T> && has_member_begin_or_end<T>; 
    } && 
    requires (begin_mf_t<declref_t<T>> _begin, 
       end_mf_t<declref_t<T>> _end) { 
     { _begin!=_end } -> bool; 
     { *_begin } -> auto&&; 
     { ++_begin }; 
    } || 
    /*Types with non-member begin/end*/ 
    requires { 
     requires !std::is_class_v<T> || !has_member_begin_or_end<T>; 
    } && 
    requires (begin_non_mf_t<declref_t<T>> _begin, 
       end_non_mf_t<declref_t<T>> _end) { 
     { _begin!=_end } -> bool; 
     { *_begin } -> auto&&; 
     { ++_begin }; 
    }; 

और परीक्षण के मामले।

#include <vector> 

// Evaluates to true or diagnoses which constraints failed. 
template <Range> constexpr bool is_range {true}; 

static_assert(!Range<void>); 
static_assert(!Range<int>); 
static_assert(!Range<int*>); 
static_assert(!Range<int[]>); 
static_assert(is_range<int[1]>); 
static_assert(is_range<std::vector<int>>); 

struct A { }; 
struct B { 
    int begin; 
}; 
struct C { 
    int* begin(); 
    int* end(); 
}; 
struct D { }; 
struct E { 
    int end; 
}; 
enum F { }; 
struct G { 
    int* begin() &&; 
    int* end(); 
}; 
struct H { 
    int* begin() &&; 
    int* end() &&; 
}; 
int* begin(D); 
int* end(D); 
int* begin(E); 
int* end(E); 
int* begin(F); 
int* end(F); 
int* begin(H); 
int* end(H); 

static_assert(!Range<A>); 
static_assert(!Range<B>); 
static_assert(is_range<C>); 
static_assert(is_range<D>); 
static_assert(!Range<E>); 
static_assert(is_range<F>); 
static_assert(!Range<G>); 
static_assert(!Range<H>); 

int main() { } 
+1

ऐसा नहीं है कि वजह से कैसे कल्पना लिखा है करने के लिए एक चेतावनी जोड़ने के लिए अच्छा है, उपयोगकर्ता कोड केवल अवधारणा-ifying पर एक सबसे अच्छा प्रयास का प्रयास कर सकते हैं यह भाषा सुविधा (हालांकि एक बहुत अच्छा है)। वहां (बहुत) पैथोलॉजिकल एज केस हैं जिन्हें पकड़ा नहीं जा सकता है। –

+0

@ ल्यूकडैंटन मैंने नामित चर पर काम करने के लिए अवधारणा को फिर से लिखा है, जैसा कि श्रेणी-अर्थशास्त्र के लिए आवश्यक है। हालांकि, जोड़ा गया परीक्षण केस विफल रहता है, और मुझे नहीं पता क्यों। क्या यह एक बढ़िया मामला हो सकता है, जैसा कि आपने पहले उल्लेख किया था? –

+0

मुझे पिछले समाधान के साथ नए टेस्ट केस का परीक्षण छोड़ना नहीं चाहिए था। मैंने इसे जोड़ा 'declref' संकेत के माध्यम से तय कर दिया है। हरचीज के लिए धन्यवाद। –

0

P0587 के अनुसार, इस लिए पर्याप्त होना चाहिए:

#include <vector> 

template<typename T> 
concept bool RangeForAble = requires (T t) { 
    requires requires (decltype(begin(t)) b, decltype(end(t)) e) { 
    b != e; 
    ++b; 
    *b; 
    }; 
}; 

int main() 
{ 
static_assert(RangeForAble<std::vector<int>>); 
static_assert(RangeForAble<double>); 
} 
संबंधित मुद्दे