2011-09-28 26 views
8

在他最近的一次谈话中,Herb Sutter建议您优先选择container.begin()以上的免费begin(container)end(container)功能模板。我喜欢它,因为这些函数可以提供给所有不带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中不允许重载,对吗?)。尤其是关于查找基于范围的循环的最好方法是什么?

回答

8

我会让ADL做它的工作。虽然允许您在std名称空间中添加专业化,但如果名称空间中的纯自由函数足够,我可以认为没有理由这么做。

在特别是用于循环的范围内,标准状态:

§6.5.4/ 1(的定义开始 - EXPR端EXPR):

  • 否则,begin-expr和end-expr分别是begin(__range)end(__range),其中begin和end分别用参数相关查找(3.4.2)进行查找。为了查找这个名称,namespace std是一个关联的名称空间。
4

这很完美,建议依靠ADL。 beginend函数是你类型接口的一部分(不管它们是否是独立函数),它们应该和你的类型在同一个命名空间中。