在他最近的一次会谈中,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中重载,对吧?)。特别是关于查找基于范围的循环的最佳方法是什么?
答案 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。 begin
和end
函数是类型接口的一部分(无论它们是否为独立函数),它们应与您的类型位于同一名称空间中。