对于for-range循环语法,如何使原始指针的行为像一个范围。

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

动机:

现在,可以将boost::optional(将来的std::optional)值视为一个范围,并因此在for范围循环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;。很好,但是我想实现上面的其他语法。

尝试

首先,我尝试使上述Optionalbeginend版本适用于指针,但我做不到。因此,我决定要明确类型,并删除所有模板:
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-range循环:
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

最佳答案

因为基于范围的工作方式是(来自第6.5.4节):



在这种情况下,关联的 namespace 是什么? (第3.4.2/2条,重点是我的):



因此,没有地方放置您的double* begin(double*),以便基于范围的for语句将其调用。

一种解决方案,您只需做一个简单的包装即可:

template <typename T>
struct PtrWrapper {
    T* p;
    T* begin() const { return p; }
    T* end() const { return p ? p+1 : nullptr; }
};

for (double& d : PtrWrapper<double>{dptr}) { .. }

10-04 21:54
查看更多