重载指向集合的指针的开始/结束是否是个好主意

Is it a good idea to overload begin/end for pointers to collections

本文关键字:结束 是否是 好主意 指针 集合 重载 开始      更新时间:2023-10-16

我真的很喜欢自由begin end的新概念来编写更通用的算法和数据结构。目前,我有时会遇到这样的情况,当类型将对集合的引用作为指针时,我必须区分调用begin(range)begin(*range)。我想过总是为我自己的集合类型的指针提供开始/结束的重载是否是一个好主意。

struct Container {
    int values[3];
};
const int* begin(const Container& c);
const int* end(const Container& c);
const int* begin(const Container* c);
const int* end(const Container* c);
template<typename Range>
int Sum(const Range& range)
{
    return std::accumulate(begin(range), end(range), 0);
}
int main(void)
{
    Container c = {1, 2, 3};
    std::cout << Sum(c);
    std::cout << Sum(&c);
}

如果这是一个好主意,为什么不为此提供一个模板:

template<typename Range>
auto begin(const Range* r) -> decltype(begin(*r)){
    using std::begin;
    return begin(*r);
}
template<typename Range>
auto end(const Range* r) -> decltype(end(*r)) { /* ... */ }
int main(void)
{
    Container c = {1, 2, 3};
    std::vector<int> v = {1, 2, 3}
    std::cout << Sum(c);
    std::cout << Sum(&c);
    std::cout << Sum(v);
    std::cout << Sum(&v);
}

如果这是一个好主意,为什么标准库不定义它?

我的问题是template<typename R> auto begin(const R* r)模板有什么问题吗?是否有任何情况会因某种原因而失败?

如果这样做,您将不能再对数组使用 std::begin() 和重载std::end()

Container c[2] = { };
std::accumulate(begin(c), end(c), 0);

这不应该编译,因为您无法将c[i]添加到0,但它确实如此,因为选择了begin(Container*)重载而不是泛型重载std::begin(T (&)[N])重载。

再举一个例子:

Container c[2] = { };
auto dist = std::distance(begin(c), end(c));

这应该设置为 dist=2 ,因为数组有两个元素,但你会得到dist=3 end(*c) - begin(*c)因为 等于 3。