Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to provide free begin/end functions for your own types

Tags:

c++

c++11

In one of his latest talks, Herb Sutter recommended to prefer the free begin(container) end(container) functions templates over container.begin(). I like it, because these function can be provided for all iterable types that don't come with begin()/end() methods. Since most of my domain classes have interfaces that talk in the domain language and don't use general names like begin/end, I can now provide an iterable interface compatible to STL containers and range base for loops without messing up the main class interface. I am wondering what is the best way to provide begin/end functions for my own types. My first thought was to do it the same way I do with swap and write the function in the same namespace where my type lives.

namespace My
{

class Book
{
public:
    typedef std::vector<Page>::const_iterator PageIterator;

    PageIterator FirstPage() const { return begin(pages_); }
    PageIterator LastPage() const { return end(pages_); }

private:
    std::vector<Page> pages_;
};

Book::PageIterator begin(const Book& b)
{
    return b.FirstPage();
}

Book::PageIterator end(const Book& b)
{
    return b.LastPage();
}

}

Is it ok to rely in ADL here, or should they be in std namespace? I think another way is to provide a specialization in std namespace (overloading in std is not allowed, right?). What is the best way espacially regarding lookup for range based for loops?

like image 533
hansmaad Avatar asked Sep 28 '11 12:09

hansmaad


2 Answers

I would let ADL do its work. While you are allowed to add specializations in the std namespace, there is no strong reason I can think of for doing so when a plain free function in your namespace suffices.

In particular for the range for loops, the standard states:

§6.5.4/1 (definition of begin-expr and end-expr):

  • otherwise, begin-expr and end-expr are begin(__range) and end(__range), respectively, where begin and end are looked up with argument-dependent lookup (3.4.2). For the purposes of this name lookup, namespace std is an associated namespace.
like image 145
David Rodríguez - dribeas Avatar answered Nov 16 '22 00:11

David Rodríguez - dribeas


It's perfectly OK and recommended to "rely" on ADL. The begin and end functions are part of your type's interface (regardless of whether they are freestanding functions or not) and they should be in the same namespace as your type.

like image 36
Armen Tsirunyan Avatar answered Nov 16 '22 02:11

Armen Tsirunyan