[英]How to specialize std::begin?
我正在嘗試將std::begin
專門用於自定義容器。 因為我想使用基於范圍的我這樣做是for
與容器。 這就是我所擁有的:
class stackiterator { … };
class stack { … };
#include <iterator>
template <> stackiterator std::begin(stack& S)
{
return S.GetBottom();
}
我在begin
專業化的定義中遇到以下錯誤:
沒有函數模板匹配函數模板特化“開始”
我究竟做錯了什么?
我正在嘗試將
std::begin
專門用於自定義容器。 因為我想使用基於范圍的我這樣做是for
與容器。
你正在咆哮錯誤的樹。 基於范圍的for
不使用std::begin
。 對於類類型,編譯器直接查找成員begin
和end
,如果兩者都沒有找到,則僅對ADL進行自由查找在關聯的名稱空間中begin
和end
。 不執行普通的非限定查找; 如果您的類不在std
命名空間中,則無法獲取std::begin
。
即使你想要做的特化是可能的(除非你引入一個成員begin()
否則一個函數模板的顯式特化不能改變返回類型,並且有問題的重載返回“無論成員begin()
什么begin()
返回“;而如果你介紹的會員begin()
,你為什么專業std::begin
?做它無論如何都會做),你仍然無法與使用范圍為基礎的for
。
添加自由函數的正確方法begin
,使for(:)
循環能夠在stack
的命名空間中添加一個begin(stack&)
和begin(stack const&)
函數,它們分別返回一個迭代器和一個const_iterator(和ditto for end
)
另一種方法是將成員begin()
和end()
到stack
。
專業化std::begin
是一個不好的做法,原因有很多,其中最重要的是並非所有for(:)
循環都可以使用它(查找規則在此缺陷報告的分辨率中發生了變化)。 重載std::begin
是未定義的行為(你可能不會在標准namespace std
重載函數:這樣做會使你的程序格式錯誤)。
即使它違反了項目的命名約定,也必須這樣做。
撇開是否應該從std
命名空間專門化函數模板的策略和語義問題,
以下代碼段不起作用:
class stackiterator {};
struct stack { stackiterator Begin() { return stackiterator{};} };
#include <iterator>
namespace std
{
template <> stackiterator begin<stack>(stack& S)
{
return S.Begin();
}
}
但是,以下代碼段工作正常:
class stackiterator {};
struct stack { stackiterator begin() { return stackiterator{};} };
#include <iterator>
namespace std
{
template <> stackiterator begin<stack>(stack& S)
{
return S.begin();
}
}
關鍵區別在於Begin()
vs begin()
作為stack
的成員函數。 std::begin()
定義為:
template <class C> auto begin(C& c) -> decltype(c.begin());
template <class C> auto begin(const C& c) -> decltype(c.begin());
當您專門化函數模板時,您仍必須保持返回類型相同。 當您沒有begin()
作為Stack
的成員時,編譯器不知道如何確定返回類型。
這就是編譯器產生錯誤的原因。
順便說一句,還有另一篇SO帖子 ,它部分回答了什么可以是專業的,什么是不專業的。
看看處理std::begin()
的標准部分,第24.3節,我沒有看到任何關於無法專門化std::begin()
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.