繁体   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