2011-09-28 47 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函數是你類型接口的一部分(不管它們是否是獨立函數),它們應該和你的類型在同一個命名空間中。