Th3Ya0vi / pugixml

Automatically exported from code.google.com/p/pugixml
0 stars 0 forks source link

Add begin/end free function in the pugi namespace for C++11 compatibility #170

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
C++11 adds the free functions std::begin/std::end. There default
implementation in namespace std will call the respective begin/end
member functions and that should do the trick. However, std::begin/end
are supposed to be called unqualified to leverage ADL. The problem
with this is, that std::begin/end have to be brought into scope
explicitly when using them with pugi classes e.g.

    // required, else the calls bellow would fail
    using std::begin; 
    using std::end;

    pugi::xml_node n;
    begin(n); end(n);

This is trivial to fix by providing the appropriate free functions in
the pugi namespace or adding the two using clauses to the pugi
namespace, if the functions are available on the given compiler.

Original issue reported on code.google.com by bootsare...@gmail.com on 7 Sep 2012 at 10:00

GoogleCodeExporter commented 8 years ago
Can you tell me where I can find the suggestion to call begin/end unqualified? 
I'm not sure it is a good one.

If a user decides to use unqualified std::begin/std::end, one:
a. loses support for iterating over arrays (ADL does not work on built-in 
arrays)
b. loses support for iterating over custom library types that do not explicitly 
implement begin/end free functions

On the other hand, std::begin(v) uses v.begin() without the need to change the 
type - what value does ADL bring here?

Original comment by arseny.k...@gmail.com on 6 Mar 2013 at 4:14

GoogleCodeExporter commented 8 years ago
I should add that you only need to use all when calling begin/end with a type 
that has been passed through a template. If you don't use ADL user-supplied 
types will not work if their begin/end implementation doesn't simply call 
a.begin/end. Users are not allowed to overload begin/end so a non-adl call 
could not find their versions. 

Your first point is wrong: an unqualified call will still work for arrays due 
to the using directive. 
The second point is wrong for the same reason, if there is no begin/end for the 
type, std::begin takes care of it. 

This is the same as for generically calling std::swap. 

Original comment by bootsare...@gmail.com on 6 Mar 2013 at 4:29

GoogleCodeExporter commented 8 years ago
I'm confused. What using directive are you speaking of?

Once again, suppose you have a generic function:

template <typename T> void iter(T& container)
{
    auto it = begin(container);
    ...
}

Why would you, as a author of the iter function, use begin as opposed to 
std::begin? I do not see any benefits, and I believe the drawbacks a./b. from 
the comment #1 apply.

std::swap is very different in my opinion. The difference is that by using a 
qualified call to std::swap you are always using the generic (inefficient, 
non-customizable) version of swapping. You do not have this problem when you're 
using std::begin - it just delegates to v.begin() except for a few special 
cases, like arrays.

Original comment by arseny.k...@gmail.com on 6 Mar 2013 at 6:00

GoogleCodeExporter commented 8 years ago
I'd use an unqualified call with a using directive because I want the same 
customizable behavior for begin/end that I have for swap. This can be very 
useful when adapting types to libraries where I cannot modify the original type 
or modification would break things. Or for cases where there is no begin/end 
member but something more specified, e.g. begin_points, and you want 
compatability with range for loops. 

Original comment by bootsare...@gmail.com on 7 Mar 2013 at 4:59

GoogleCodeExporter commented 8 years ago
I've asked the question on StackOverflow and, while opinions diverged, the 
consensus is that the generic code should either use a qualified call to 
std::begin or use an unqualified call and do using std::begin so that ADL can 
work if necessary but fall back to the std:: implementation. This means that 
you can use ADL to provide iteration for containers that are not compatible 
with the standard interface, but containers that already have member begin/end 
functions do not have to do anything else.

Please refer to 
http://stackoverflow.com/questions/17562943/should-custom-containers-have-free-b
egin-end-functions

Original comment by arseny.k...@gmail.com on 10 Jul 2013 at 2:52