簡體   English   中英

如何專門化std :: begin?

[英]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 對於類類型,編譯器直接查找成員beginend ,如果兩者都沒有找到,則僅對ADL進行自由查找在關聯的名稱空間中beginend 不執行普通的非限定查找; 如果您的類不在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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM