Begin and End Non-Member Functions

85 views
Skip to first unread message

Ruud van Asseldonk

unread,
Nov 12, 2015, 4:43:25 AM11/12/15
to cxx
The begin/end non-member functions are currently on the “To Be Discussed” list. They are especially useful for using the std iterator-style APIs with fixed-size arrays. I implemented std::end for fixed-size arrays manually in several places to work around std::end being banned. Is there any harm in allowing it now?

Ryan Sleevi

unread,
Nov 12, 2015, 11:18:56 AM11/12/15
to Ruud van Asseldonk, cxx
On Thu, Nov 12, 2015 at 1:43 AM, Ruud van Asseldonk <ru...@google.com> wrote:
The begin/end non-member functions are currently on the “To Be Discussed” list. They are especially useful for using the std iterator-style APIs with fixed-size arrays. I implemented std::end for fixed-size arrays manually in several places to work around std::end being banned. Is there any harm in allowing it now?

When you say "implemented it manually", are you talking about using something other than https://code.google.com/p/chromium/codesearch#chromium/src/base/macros.h&l=47

Ruud van Asseldonk

unread,
Nov 12, 2015, 11:41:32 AM11/12/15
to cxx, ru...@google.com, rsl...@chromium.org
When you say "implemented it manually", are you talking about using something other than https://code.google.com/p/chromium/codesearch#chromium/src/base/macros.h&l=47

Yes. std::end returns a pointer past the end of an array, not the size of the array. See for example here.

Ryan Sleevi

unread,
Nov 12, 2015, 11:58:58 AM11/12/15
to Ruud van Asseldonk, cxx, Ryan Sleevi
On Thu, Nov 12, 2015 at 8:41 AM, Ruud van Asseldonk <ru...@google.com> wrote:
When you say "implemented it manually", are you talking about using something other than https://code.google.com/p/chromium/codesearch#chromium/src/base/macros.h&l=47

Yes. std::end returns a pointer past the end of an array, not the size of the array. See for example here.

Right, I meant "implemented using means other than taking start + arraysize to compute end", but the example code answered that ;) 

Dana Jansens

unread,
Nov 22, 2015, 1:24:51 PM11/22/15
to rsl...@chromium.org, Ruud van Asseldonk, cxx
This looks useful in cases like you linked to. Providing overloads will also allow iteration on things that dont expose a begin/end as member methods. Can you send a CL that updates the styleguide and makes use of begin/end so that we can see it pass the bots?

Can you mention the "using std::begin; begin(a); idiom in the notes section for the styleguide?

Thanks!
--
You received this message because you are subscribed to the Google Groups "cxx" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cxx+uns...@chromium.org.
To post to this group, send email to c...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/cxx/CACvaWvb_Oq6zDGBavmOep3pmyc8U3EUNynVHHo9Ge6_uCB8bvA%40mail.gmail.com.

Brett Wilson

unread,
Nov 22, 2015, 2:26:03 PM11/22/15
to Dana Jansens, rsl...@chromium.org, Ruud van Asseldonk, cxx
Should we just be overriding "std::begin" and "std::end" now instead of implementing it in the global namespace?

I was recently pointed at a part of the C++11 spec that says this is OK now, and making std::begin do the right thing seems better than relying on people remembering the "using" trick. Is this actually recommended nowadays?

Brett

Dana Jansens

unread,
Nov 22, 2015, 2:42:43 PM11/22/15
to Brett Wilson, rsl...@chromium.org, Ruud van Asseldonk, cxx
On Sunday, November 22, 2015, Brett Wilson <bre...@chromium.org> wrote:
Should we just be overriding "std::begin" and "std::end" now instead of implementing it in the global namespace?

I was recently pointed at a part of the C++11 spec that says this is OK now, and making std::begin do the right thing seems better than relying on people remembering the "using" trick. Is this actually recommended nowadays?

I also saw it mentioned that you can override std::begin on cppreference. But it also says that the standard library will use the using trick. So if you just call std::begin, and the. use some iteration defined in the library, you could have different things happen in each one. That left me thinking we should continue using that one weird trick. What do you think?

Daniel Cheng

unread,
Nov 22, 2015, 2:48:48 PM11/22/15
to Dana Jansens, Brett Wilson, rsl...@chromium.org, Ruud van Asseldonk, cxx
On Sun, Nov 22, 2015 at 11:42 AM 'Dana Jansens' via cxx <c...@chromium.org> wrote:
On Sunday, November 22, 2015, Brett Wilson <bre...@chromium.org> wrote:
Should we just be overriding "std::begin" and "std::end" now instead of implementing it in the global namespace?

I was recently pointed at a part of the C++11 spec that says this is OK now, and making std::begin do the right thing seems better than relying on people remembering the "using" trick. Is this actually recommended nowadays?

I also saw it mentioned that you can override std::begin on cppreference. But it also says that the standard library will use the using trick. So if you just call std::begin, and the. use some iteration defined in the library, you could have different things happen in each one. That left me thinking we should continue using that one weird trick. What do you think?

On the flip side, you could argue that defining it in namespace std is more consistent with the behavior of std::default_delete and std::hash.

Daniel
 
 

Brett

On Sun, Nov 22, 2015 at 10:24 AM, 'Dana Jansens' via cxx <c...@chromium.org> wrote:
This looks useful in cases like you linked to. Providing overloads will also allow iteration on things that dont expose a begin/end as member methods. Can you send a CL that updates the styleguide and makes use of begin/end so that we can see it pass the bots?

Can you mention the "using std::begin; begin(a); idiom in the notes section for the styleguide?

Thanks!


On Thursday, November 12, 2015, Ryan Sleevi <rsl...@chromium.org> wrote:


On Thu, Nov 12, 2015 at 8:41 AM, Ruud van Asseldonk <ru...@google.com> wrote:
When you say "implemented it manually", are you talking about using something other than https://code.google.com/p/chromium/codesearch#chromium/src/base/macros.h&l=47

Yes. std::end returns a pointer past the end of an array, not the size of the array. See for example here.

Right, I meant "implemented using means other than taking start + arraysize to compute end", but the example code answered that ;) 

--
You received this message because you are subscribed to the Google Groups "cxx" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cxx+uns...@chromium.org.
To post to this group, send email to c...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/cxx/CACvaWvb_Oq6zDGBavmOep3pmyc8U3EUNynVHHo9Ge6_uCB8bvA%40mail.gmail.com.

--
You received this message because you are subscribed to the Google Groups "cxx" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cxx+uns...@chromium.org.
To post to this group, send email to c...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/cxx/CAHtyhaS_5i0es1E9%2BOWiNLO71gX9JmoAA-BKqaETPSxmm2Yb7g%40mail.gmail.com.

--
You received this message because you are subscribed to the Google Groups "cxx" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cxx+uns...@chromium.org.
To post to this group, send email to c...@chromium.org.

Dana Jansens

unread,
Nov 22, 2015, 3:00:45 PM11/22/15
to Daniel Cheng, Brett Wilson, rsl...@chromium.org, Ruud van Asseldonk, cxx
On Sunday, November 22, 2015, Daniel Cheng <dch...@chromium.org> wrote:
On Sun, Nov 22, 2015 at 11:42 AM 'Dana Jansens' via cxx <c...@chromium.org> wrote:
On Sunday, November 22, 2015, Brett Wilson <bre...@chromium.org> wrote:
Should we just be overriding "std::begin" and "std::end" now instead of implementing it in the global namespace?

I was recently pointed at a part of the C++11 spec that says this is OK now, and making std::begin do the right thing seems better than relying on people remembering the "using" trick. Is this actually recommended nowadays?

I also saw it mentioned that you can override std::begin on cppreference. But it also says that the standard library will use the using trick. So if you just call std::begin, and the. use some iteration defined in the library, you could have different things happen in each one. That left me thinking we should continue using that one weird trick. What do you think?

On the flip side, you could argue that defining it in namespace std is more consistent with the behavior of std::default_delete and std::hash.

Ya absolutely. I was actually thinking of recommending that you define your own begin/end in std. But I was worried that it'd be hard to enforce, and so recommend the using trick as a general rule when calling begin/end. 

If we could be sure all non-standard begin/ends we use were actually in std:: that would make me feel better also. 

Brett Wilson

unread,
Nov 22, 2015, 3:05:34 PM11/22/15
to Dana Jansens, Daniel Cheng, rsl...@chromium.org, Ruud van Asseldonk, cxx
On Sun, Nov 22, 2015 at 12:00 PM, Dana Jansens <dan...@google.com> wrote:
On Sunday, November 22, 2015, Daniel Cheng <dch...@chromium.org> wrote:
On Sun, Nov 22, 2015 at 11:42 AM 'Dana Jansens' via cxx <c...@chromium.org> wrote:
On Sunday, November 22, 2015, Brett Wilson <bre...@chromium.org> wrote:
Should we just be overriding "std::begin" and "std::end" now instead of implementing it in the global namespace?

I was recently pointed at a part of the C++11 spec that says this is OK now, and making std::begin do the right thing seems better than relying on people remembering the "using" trick. Is this actually recommended nowadays?

I also saw it mentioned that you can override std::begin on cppreference. But it also says that the standard library will use the using trick. So if you just call std::begin, and the. use some iteration defined in the library, you could have different things happen in each one. That left me thinking we should continue using that one weird trick. What do you think?

On the flip side, you could argue that defining it in namespace std is more consistent with the behavior of std::default_delete and std::hash.

Ya absolutely. I was actually thinking of recommending that you define your own begin/end in std. But I was worried that it'd be hard to enforce, and so recommend the using trick as a general rule when calling begin/end. 

If we could be sure all non-standard begin/ends we use were actually in std:: that would make me feel better also.

If you define begin/end inside of std:: and do using, you'll still get the correct result. If you do the reverse, you won't.

So I think it should always be better to recommend defining begin/end inside of std::. I personally think using looks bad and is difficult to remember, and if we define begin/end inside of std:: you don't need it.

Brett

Jeffrey Yasskin

unread,
Nov 23, 2015, 1:36:46 AM11/23/15
to Brett Wilson, cxx, Ruud van Asseldonk, Dana Jansens, rsl...@chromium.org

By "override", do you mean "overload" or "specialize"? What part of the C++11 spec were you pointed at?

http://eel.is/c++draft/namespace.std says "The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std unless otherwise specified. A program may add a template specialization for any standard library template to namespace std only if the declaration depends on a user-defined type and the specialization meets the standard library requirements for the original template and is not explicitly prohibited."

That bans overloads of std::begin() unless some other text explicitly allows it, and I'm not finding that text. I think http://en.cppreference.com/w/cpp/iterator/begin#User-defined_overloads is alluding to the fact that users can define begin() overloads in their own namespaces, which allows `using std::begin; begin(arg);` to find both.

Specializations are allowed, but because function templates can't be partially specialized, you can't specialize std::begin for a template type like a container. So you have to fall back to ADL overloads anyway in some cases, meaning you can't get away from the "using std::begin" in generic code, so you may as well use the simple same-namespace overload syntax in all cases.

Jeffrey

Brett Wilson

unread,
Nov 23, 2015, 2:33:40 AM11/23/15
to Jeffrey Yasskin, cxx, Ruud van Asseldonk, Dana Jansens, rsl...@chromium.org
On Sun, Nov 22, 2015 at 10:36 PM, Jeffrey Yasskin <jyas...@google.com> wrote:

By "override", do you mean "overload" or "specialize"? What part of the C++11 spec were you pointed at?

http://eel.is/c++draft/namespace.std says "The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std unless otherwise specified. A program may add a template specialization for any standard library template to namespace std only if the declaration depends on a user-defined type and the specialization meets the standard library requirements for the original template and is not explicitly prohibited."

That bans overloads of std::begin() unless some other text explicitly allows it, and I'm not finding that text. I think http://en.cppreference.com/w/cpp/iterator/begin#User-defined_overloads is alluding to the fact that users can define begin() overloads in their own namespaces, which allows `using std::begin; begin(arg);` to find both.

Specializations are allowed, but because function templates can't be partially specialized, you can't specialize std::begin for a template type like a container. So you have to fall back to ADL overloads anyway in some cases, meaning you can't get away from the "using std::begin" in generic code, so you may as well use the simple same-namespace overload syntax in all cases.

I see what you mean, I was thinking this usage would fall under specialization.

I sort of hijacked this "can I call std::begin and std::end thread" because I got sidetracked on how to override them. Sorry about this. It's exceptionally hard to come up with a case where an overload of begin and end is useful. We should allow using std::begin and std::end. I don't think we should issue advice about the "using" thing.

Ruud's original message was just that wanted to iterate over a fixed size array. It should be permissible to assume that std::begin and std::end do the right thing for these, as well as for any normal container. If somebody is writing a custom container, they should write member begin and end like normal, and everything will just work with the std:: versions. If somebody is writing really really generic algorithm code it's probably a good idea to do the using thing, but I think it's uncommon enough that putting a rule for this in the style guide is not worth the addition of complexity to the document (which makes it harder to follow). Also, if you forget the using thing and somebody calls your algorithm expecting this behavior, it will fail to compile in any reasonable case. This is different than forgetting it for std::swap which runs slower without telling you.

Brett

Jeffrey Yasskin

unread,
Nov 23, 2015, 2:48:21 AM11/23/15
to Brett Wilson, cxx, Ruud van Asseldonk, Dana Jansens, rsl...@chromium.org
Right, a template specialization is a specific set of things that
don't include new overloads.

> I sort of hijacked this "can I call std::begin and std::end thread" because
> I got sidetracked on how to override them. Sorry about this. It's
> exceptionally hard to come up with a case where an overload of begin and end
> is useful. We should allow using std::begin and std::end. I don't think we
> should issue advice about the "using" thing.
>
> Ruud's original message was just that wanted to iterate over a fixed size
> array. It should be permissible to assume that std::begin and std::end do
> the right thing for these, as well as for any normal container. If somebody
> is writing a custom container, they should write member begin and end like
> normal, and everything will just work with the std:: versions. If somebody
> is writing really really generic algorithm code it's probably a good idea to
> do the using thing, but I think it's uncommon enough that putting a rule for
> this in the style guide is not worth the addition of complexity to the
> document (which makes it harder to follow). Also, if you forget the using
> thing and somebody calls your algorithm expecting this behavior, it will
> fail to compile in any reasonable case. This is different than forgetting it
> for std::swap which runs slower without telling you.

Blindly calling either std::begin(c) or c.begin() instead of going
through the 'using' dance in nearly all cases SGTM, as does the advice
to define ns::C::begin() instead of ns::begin(const C&). I don't care
about putting any of this in the style guide, as long as we don't
recommend overloading or specializing std::begin(). :)

Jeffrey

Nico Weber

unread,
Nov 23, 2015, 11:03:37 AM11/23/15
to Jeffrey Yasskin, Brett Wilson, cxx, Ruud van Asseldonk, Dana Jansens, rsl...@chromium.org
+1 to all of this. Ruud, can you send a CL to move std::begin() / std::end() to the "allowed" section, and also add at least one call to std::begin()/std::end() in that CL so that the try bots can check that this actually builds everywhere?

I don't think we need to add much guidance on how to use it. If people write new containers (which is relatively rare) they'll hopefully give them begin() / end() member functions instead of putting a specialization into std (since that seems like the more obvious thing to do, I think), and then everything will just work.
 

Jeffrey


--
You received this message because you are subscribed to the Google Groups "cxx" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cxx+uns...@chromium.org.
To post to this group, send email to c...@chromium.org.

Ruud van Asseldonk

unread,
Nov 23, 2015, 11:22:37 AM11/23/15
to cxx, jyas...@google.com, bre...@chromium.org, ru...@google.com, dan...@google.com, rsl...@chromium.org
Reply all
Reply to author
Forward
0 new messages