lundi 3 juin 2019

Overloading std::begin() and std::end() for non-arrays

Let's assume I have the following Data class:

struct Data {
   char foo[8];
   char bar;
};

and the following function, my_algorithm, which takes a pair of char * (similar to an STL algorithm):

void my_algorithm(char *first, char *last);

For Data's foo data member, instead of calling my_algorithm() like this:

Data data;
my_algorithm(data.foo, data.foo + 8);

I can use the std::begin() and std::end() convenience function templates:

my_algorithm(std::begin(data.foo), std::end(data.foo));

I would like to achieve something similar to Data's bar data member. That is, instead of writing:

my_algorithm(&data.bar, &data.bar + 1);

I would like to write something like:

my_algorithm(begin(data.bar), end(data.end));

Therefore, I've defined the two following ordinary (non-template) functions for this case:

char* begin(char& c) { return &c; }
char*   end(cahr& c) { return &c + 1; }

So that I would be able to write code like the following:

Data data;

using std::begin;
using std::end;

my_algorithm(begin(data.foo), end(data.foo)); // ok - std::begin()/std::end()
my_algorithm(begin(data.bar), end(data.bar)); // Error!!!

With the using declarations above I would have expected std::begin()/std::end() and ::begin()/::end() to be in the same overload set, respectively. Since the functions ::begin() and ::end() are a perfect match for the latter call and they are not templates, I would have expected the last call to my_algorithm() to match them. However, the ordinary functions are not considered at all. As a result the compilation fails, because std::begin() and std::end() are not matches for the call.

Basically, the latter call acts as if I had written instead:

my_algorithm(begin<>(data.bar), end<>(data.bar));

That is, only the function templates (i.e., std::begin()/std::end()) are considered by the overload resolution process, not the ordinary functions (i.e., not ::begin()/::end()).

It only works as expected, if I fully qualify the calls to ::begin()/::end():

my_algorithm(::begin(data.bar), ::end(data.bar));

What am I missing here?

Aucun commentaire:

Enregistrer un commentaire