[英]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.