vendredi 30 janvier 2015

Viewing a raw pointer as a range in range-based for-loop

How can I make a raw pointer behave like a range, for a for-range loop syntax.



double five = 5;
double* dptr = &five;
for(int& d : dptr) std::cout << d << std::endl;// will not execute if the pointer is null


Motivation:


It is now vox populi that an boost::optional (future std::optional) value can be viewed as a range and therefore used in a for range loop http://ift.tt/1HswM4U.


When I rewrote my own simplified version of it:



namespace boost {
template <class Optional>
decltype(auto) begin(Optional& opt) noexcept{
return opt?&*opt:nullptr;
}

template <class Optional>
decltype(auto) end(Optional& opt) noexcept{
return opt?std::next(&*opt):nullptr;
}
}


Used as



boost::optional<int> opt = 3;
for (int& x : opt) std::cout << x << std::endl;


While looking that code I imagined that it could be generalized to raw (nullable) pointers as well.



double five = 5;
double* dptr = &five;
for(int& d : dptr) std::cout << d << std::endl;


instead of the usual if(dptr) std::cout << *dptr << std::endl;. Which is fine but I wanted to achieve the other syntax above.


Attempts


First I tried to make the above Optional version of begin and end work for pointers but I couldn't. So I decided to be explicit in the types and remove all templates:



namespace std{ // excuse me, this for experimenting only
double* begin(double* opt){
return opt?&*opt:nullptr;
}
double* end(double* opt){
return opt?std::next(&*opt):nullptr;
}
}


Almost there, it works for



for(double* ptr = std::begin(dptr); ptr != std::end(dptr); ++ptr)
std::cout << *ptr << std::endl;


But it doesn't work for the supposedly equivalent for-range loop:



for(double& d : dptr) std::cout << d << std::endl;


Two compilers tell me: error: invalid range expression of type 'double *'; no viable 'begin' function available


What is going on? Is there a compiler magic that forbids the ranged-loop to to work for pointers. Am I making a wrong assumption about the ranged-loop syntax?


Ironically, in the standard there is an overload for std::begin(T(&arr)[N]) and this is very close to it.


Aucun commentaire:

Enregistrer un commentaire