#include <iostream>
#include <type_traits>
template< typename type >
type const & as_const( type const & ref )
{ return ref; }
template< typename type >
typename std::enable_if< ! std::is_reference< type >::value,
type >::type const as_const( type && val )
{ return std::move( val ); }
struct rng {
struct it {
it ( int in ) : i( in ) {}
int i;
int operator * () const { std::cout << "non-const\n"; return i; }
it & operator ++ () { ++ i; return * this; }
bool operator != ( it rhs ) { return i != rhs.i; }
};
struct cit : it {
using it::it;
int operator * () const { std::cout << "const\n"; return i; }
};
it begin() { return { 0 }; }
it end() { return { 5 }; }
cit begin() const { return { 0 }; }
cit end() const { return { 5 }; }
rng() { std::cout << "make range\n"; }
rng( rng && ) { std::cout << "move range\n"; }
rng( rng const & ) { std::cout << "copy range\n"; }
~ rng() { std::cout << "destroy range\n"; }
};
int main () {
std::cout << "non-const temp\n";
for ( auto i : rng() ) ;
std::cout << "\nconst temp\n";
for ( auto i : as_const( rng() ) ) ;
std::cout << "\nconst non-temp\n";
rng r;
for ( auto i : as_const( r ) ) ;
}