2013-08-28 2 views
7

Il C++ 11 non ha un loop per la sequenza integrale a intervalli.loop basato su intervallo C++ 11 per intervallo (L, R)

for(auto e : {0..10}) // wouldn't compile!!! 

Quindi ho appena deciso di simularlo.

template< class T , bool enable = std::is_integral<T>::value > 
struct range_impl 
{ 
    struct iterator 
    { 
     constexpr T operator *()const noexcept { return value; } 
     iterator& operator ++()noexcept { ++value; return *this; } 

     friend 
     constexpr bool operator != (const iterator & lhs, const iterator rhs) noexcept 
     { 
      return lhs.value != rhs.value; 
     } 
     T value; 
    }; 

    constexpr iterator begin()const noexcept { return { first }; } 
    constexpr iterator end ()const noexcept { return { last }; } 

    T first; 
    T last ; 
}; 




template< class T > 
range_impl<T> range(T first , T last) noexcept 
{ 
    return {first, last}; 
} 

int main(){ 
    // print numbers in [ 0..10), i.e. 0 1 2 3 4 5 6 7 8 9 
    for(auto e : range(0,10)) std::cout << e << ' '; 
    std::cout << std::endl; 
} 

Q: Come generalizzare questo metodo per ForwardIterators?

esempio:

template< class ForwardIterator, class T > 
bool find(ForwardIterator first, ForwardIterator last, T const& value) 
{ 
    for(auto e: range(first, last)) if (e == v) return true; 
    return false; 
} 
+3

che non è veramente * * generalizzare esso; gli interi non sono iteratori. Stai praticamente facendo una nuova funzione con lo stesso nome. –

risposta

6

Specializzazione

template< class Iterator> 
struct range_impl<Iterator, false> 
{ 
    range_impl(Iterator first, Iterator last) 
    : first(first), last(last) 
    {} 

    constexpr Iterator begin()const noexcept { return { first }; } 
    constexpr Iterator end ()const noexcept { return { last }; } 

    Iterator first; 
    Iterator last ; 
}; 

prova:

int main(){ 
    for(auto e : range(0,10)) std::cout << e << ' '; 
    std::cout << std::endl; 
    const char* a[] = { "Say", "hello", "to", "the", "world" }; 
    for(auto e : range(a, a + 5)) std::cout << e << ' '; 
    std::cout << std::endl; 
} 
+0

È inoltre possibile rimuovere l'implementazione dell'intervallo basato su numero intero. Invece, crea un iteratore intero e passalo all'implementazione dell'intervallo basato sull'iteratore (riduci la duplicazione del codice!). Un'altra cosa che la mia implementazione personale di questo fa è che ha 'size' e' [] 'definiti se l'iteratore è ad accesso casuale, e il mio intero iteratore è ad accesso casuale. – Yakk

1

Si sta cercando di reimplementare boost::iterator_range e boost::counting_iterator. Basta fare questo, invece:

template< class T > 
boost::iterator_range< boost::counting_iterator<T> > range(T const& tBegin, T const& tEnd) { 
    return boost::iterator_range< boost::counting_iterator<T> >(tBegin, tEnd); 
} 

C'è anche esiste un boost::counting_range già: http://www.boost.org/doc/libs/1_47_0/libs/range/doc/html/range/reference/ranges/counting_range.html

+0

per (auto e: temporaryObject {}); - per questo caso cosa dire standard, cioè garantisce che il tempo di vita temporaneo dell'oggetto terminato dopo il ciclo o no? –

+0

Ho tolto questo paragrafo. Sono stato parzialmente in errore. Vedi qui: http://stackoverflow.com/questions/9657708/c11-the-range-based-for-statement-range-init-lifetime – Sebastian

+0

@KhurshidNormuradov sì, muore. La semantica di loop basati su loop è chiara (è possibile implementare esempi di google) e la durata di oggetti temporanei creati durante tale periodo (la durata di un vincolo temporaneo a un riferimento è la durata di quel riferimento). – Yakk