Просмотр необработанного указателя как диапазона в цикле for на основе диапазона
Как я могу сделать необработанный указатель вести себя как диапазон, для синтаксиса цикла для диапазона.
double five = 5;
double* dptr = &five;
for(int& d : dptr) std::cout << d << std::endl;// will not execute if the pointer is null
Мотивация:
Теперь это Vox Populi, чтоboost::optional
(будущееstd::optional
) значение можно рассматривать как диапазон и, следовательно, использовать в цикле для диапазонаhttp://faithandbrave.hateblo.jp/entry/2015/01/29/173613.
Когда я переписал свою собственную упрощенную версию:
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;
}
}
Используется в качестве
boost::optional<int> opt = 3;
for (int& x : opt) std::cout << x << std::endl;
Просматривая этот код, я представлял, что он может быть обобщен и на необработанные (обнуляемые) указатели.
double five = 5;
double* dptr = &five;
for(int& d : dptr) std::cout << d << std::endl;
вместо обычногоif(dptr) std::cout << *dptr << std::endl;
, Что хорошо, но я хотел добиться другого синтаксиса выше.
попытки
Сначала я попытался сделать вышеOptional
версияbegin
а такжеend
работать для указателей, но я не мог. Поэтому я решил быть явным в типах и удалить все шаблоны:
namespace std{ // excuse me, this for experimenting only, the namespace can be removed but the effect is the same.
double* begin(double* opt){
return opt?&*opt:nullptr;
}
double* end(double* opt){
return opt?std::next(&*opt):nullptr;
}
}
Почти там, это работает для
for(double* ptr = std::begin(dptr); ptr != std::end(dptr); ++ptr)
std::cout << *ptr << std::endl;
Но это не работает дляпредположительно эквивалентный петля для диапазона:
for(double& d : dptr) std::cout << d << std::endl;
Два компилятора говорят мне:error: invalid range expression of type 'double *'; no viable 'begin' function available
Что здесь происходит? Есть ли магия компилятора, которая запрещает дальний цикл работать для указателей. Я делаю неправильное предположение о синтаксисе дальнего цикла?
Как ни странно, в стандарте есть перегрузка дляstd::begin(T(&arr)[N])
и это очень близко к этому.
Обратите внимание и секунду, хотя
Да, идея глупа, потому что, даже если это возможно, это очень сбивает с толку:
double* ptr = new double[10];
for(double& d : ptr){...}
будет перебирать только первый элемент. Более понятный и реалистичный способ - сделать что-то вроде обходного пути, предложенного @Yakk:
for(double& d : boost::make_optional_ref(ptr)){...}
Таким образом, ясно, что мы выполняем итерации только по одному элементу и этот элемент является необязательным.
Хорошо, хорошо, я вернусь кif(ptr) ... use *ptr
.