The established idiom for invoking swap
is:
using std::swap
swap(foo, bar);
This way, swap
can be overloaded for user
Disclaimer: For the pedantic types (or pedants, if you want to be pedantic...), I generally refer to the word "overload" here as "Create functions that have the names begin
and end
and do using std::begin; using std::end;
.", which, believe me, is not tedious for me to write at all, but is very hard to read and is redundant to read. :p.
I'll basically give you the possible use-cases of such technique, and later my conclusion.
begin
and end
methods do not act like those of the standard containersOne situation where you may need to overload the std::begin
and std::end
functions is when you're using the begin
and end
methods of your type in a different way other than to provide iterator-like access to the elements of an object, and want to have overloads of std::begin
and std::end
call the begin and end methods used for iteration.
struct weird_container {
void begin() { std::cout << "Start annoying user." }
void end() { std::cout << "Stop annoying user." }
iterator iter_begin() { /* return begin iterator */ }
iterator iter_end() { /* return end iterator */ }
};
auto begin(weird_container& c) {
return c.iter_begin();
}
auto end(weird_container& c) {
return c.iter_end();
}
However, you wouldn't and shouldn't do such a crazy thing as range-for would break if used with an object of weird_container
, as per rules of range-for, the weird_container::begin()
and weird_container::end()
methods would be found before the stand-alone function variants.
This case therefore brings an argument not to use what you have proposed, as it would break one very useful feature of the language.
begin
and end
methods aren't defined at allAnother case is when you don't define the begin
and end
methods. This is a more common and applicable case, when you want to extend your type to be iteratable without modifying the class interface.
struct good_ol_type {
...
some_container& get_data();
...
};
auto begin(good_ol_type& x) {
return x.get_data().begin();
}
auto end(good_ol_type& x) {
return x.get_data().end();
}
This would enable you to use some nifty features on good_ol_type
(algorithms, range-for, etc) without actually modifying its interface! This is in line with Herb Sutter's recommendation of extending the functionality of types through non-member non-friend functions.
This is the good case, the one where you actually want to overload std:;begin
and std::end
.
As I haven't ever seen someone do something like that of the first case (except for my example), then you'd really want to use what you've proposed and overload std::begin
and std::end
wherever applicable.
I did not include here the case where you defined both begin
and end
methods, and begin
and end
functions that does different things than the methods. I believe such a situation is contrived, ill-formed and/or done by a programmer who haven't had much experience delving into the debugger or reading novel template errors.