Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I really like the new concept of free begin end to write more generic algorithms and data structures. Currently it sometimes happens to me that I have to differentiate between calls begin(range) and begin(*range) when a type holds a reference to a collection as pointer. I thought about if it is a good idea to always provide an overload of begin/end for pointers for my own collection types.

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);
}

If this was a good idea why not provide a template for this:

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);
}

If this was a good idea why doesn't the standard library define it?

My question is: Is there anything wrong with a template<typename R> auto begin(const R* r) template? Are there any cases where this fails for some reason?

like image 788
hansmaad Avatar asked Dec 17 '12 16:12

hansmaad


1 Answers

If you do this you can no longer use std::begin() and std::end() overloaded for arrays:

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

This shouldn't compile, because you can't add c[i] to 0, but it does because the begin(Container*) overloads are selected instead of the generic std::begin(T (&)[N]) one.

For another example:

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

this should set dist=2, because the array has two elements, but instead you get dist=3 because end(*c) - begin(*c) equals 3.

like image 169
Jonathan Wakely Avatar answered Nov 03 '22 08:11

Jonathan Wakely