如何为您自己的类型提供免费的开始/结束功能

时间:2011-09-28 12:03:59

标签: c++ c++11

在他最近的一次会谈中,Herb Sutter建议更喜欢免费的begin(container) end(container)函数模板而不是container.begin()。我喜欢它,因为可以为所有不带有begin()/ end()方法的可迭代类型提供这些函数。由于我的大多数域类都具有以域语言进行通信的接口,并且不使用诸如begin / end之类的通用名称,因此我现在可以提供与STL容器兼容的可迭代接口和用于循环的范围,而不会弄乱主类接口。 我想知道为我自己的类型提供开始/结束函数的最佳方法是什么。我的第一个想法是以与swap相同的方式执行此操作,并将该函数写入我的类型所在的同一命名空间中。

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();
}

}

可以在这里依赖ADL,还是应该在std命名空间中?我认为另一种方法是在std命名空间中提供特化(不允许在std中重载,对吧?)。特别是关于查找基于范围的循环的最佳方法是什么?

2 个答案:

答案 0 :(得分:8)

我会让ADL做它的工作。虽然您可以在std命名空间中添加特殊化,但是当命名空间中的普通自由函数足够时,我没有理由这么做。

特别是对于循环范围,标准规定:

  

§6.5.4/ 1( begin-expr end-expr 的定义):

     
      
  • 否则,begin-expr和end-expr分别为begin(__range)end(__range),其中使用参数依赖查找(3.4.2)查找begin和end。出于此名称查找的目的,namespace std是一个关联的命名空间。
  •   

答案 1 :(得分:4)

完全没问题,建议“依赖”ADL。 beginend函数是类型接口的一部分(无论它们是否为独立函数),它们应与您的类型位于同一名称空间中。