1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
|
#include <iostream>
#include <list>
#include <iterator>
#include <stdexcept>
namespace detail
{
template < typename SEQUENCE_CONTAINER > // random access iterator
typename SEQUENCE_CONTAINER::const_reference
at( const SEQUENCE_CONTAINER& seq, typename SEQUENCE_CONTAINER::size_type pos, std::random_access_iterator_tag )
{ return seq.at(pos) ; }
template < typename SEQUENCE_CONTAINER > // bidirectional iterator
typename SEQUENCE_CONTAINER::const_reference
at( const SEQUENCE_CONTAINER& seq, typename SEQUENCE_CONTAINER::size_type pos, std::bidirectional_iterator_tag )
{
const auto sz = seq.size() ;
// check for valid position
if( pos >= sz ) throw std::out_of_range( "invalid position" ) ;
// if the position is in the first half of the sequence iterate forward from begin
// http://en.cppreference.com/w/cpp/iterator/next
if( pos <= sz/2 ) return *std::next( seq.begin(), pos ) ;
// if the position is in the second half of the sequence iterate backwards from end
else return *std::next( seq.rbegin(), sz-pos-1 ) ;
}
template < typename SEQUENCE_CONTAINER > // forward iterator
typename SEQUENCE_CONTAINER::const_reference
at( const SEQUENCE_CONTAINER& seq, typename SEQUENCE_CONTAINER::size_type pos, std::forward_iterator_tag )
{
const auto sz = seq.size() ;
// check for valid position
if( pos >= sz ) throw std::out_of_range( "invalid position" ) ;
return *std::next( seq.begin(), pos ) ;
}
}
template < typename SEQUENCE_CONTAINER >
typename SEQUENCE_CONTAINER::const_reference
at( const SEQUENCE_CONTAINER& seq, typename SEQUENCE_CONTAINER::size_type pos )
{ return detail::at( seq, pos, typename std::iterator_traits< decltype(seq.begin()) >::iterator_category{} ) ; }
template < typename SEQUENCE_CONTAINER >
typename SEQUENCE_CONTAINER::reference
at( SEQUENCE_CONTAINER& seq, typename SEQUENCE_CONTAINER::size_type pos )
{
const auto& const_ref = at( const_cast< const SEQUENCE_CONTAINER& >(seq), pos ) ;
return const_cast< typename SEQUENCE_CONTAINER::reference >(const_ref) ;
}
int main()
{
struct example { int value ; /* ...... */ };
std::list<example> my_list { {0}, {1}, {2}, {3}, {4}, {5} } ;
try
{
for( std::size_t pos : { 1, 4, 9 } )
{
std::cout << "my_list[" << pos << "] == " ;
example& ex = at( my_list, pos ) ;
std::cout << "example{" << ex.value << "}\n" ;
}
}
catch( const std::out_of_range& error )
{
std::cerr << " ***error: " << error.what() << '\n' ;
}
}
|