[英]How to specialize std::begin?
I'm trying to specialize std::begin
for a custom container. 我正在尝试将
std::begin
专门用于自定义容器。 I'm doing this because I want to use range-based for
with the container. 因为我想使用基于范围的我这样做是
for
与容器。 This is what I have: 这就是我所拥有的:
class stackiterator { … };
class stack { … };
#include <iterator>
template <> stackiterator std::begin(stack& S)
{
return S.GetBottom();
}
I get the following error at the definition of my begin
specialization: 我在
begin
专业化的定义中遇到以下错误:
No function template matches function template specialization 'begin'
没有函数模板匹配函数模板特化“开始”
What am I doing wrong? 我究竟做错了什么?
I'm trying to specialize
std::begin
for a custom container.我正在尝试将
std::begin
专门用于自定义容器。 I'm doing this because I want to use range-basedfor
with the container.因为我想使用基于范围的我这样做是
for
与容器。
You are barking up the wrong tree. 你正在咆哮错误的树。 Range-based
for
does not use std::begin
at all. 基于范围的
for
不使用std::begin
。 For class types, the compiler looks up member begin
and end
directly, and if neither is found, does an ADL-only lookup for free begin
and end
in the associated namespaces. 对于类类型,编译器直接查找成员
begin
和end
,如果两者都没有找到,则仅对ADL进行自由查找在关联的名称空间中begin
和end
。 Ordinary unqualified lookup is not performed; 不执行普通的非限定查找; there's no way for
std::begin
to be picked up if your class is not in the std
namespace. 如果您的类不在
std
命名空间中,则无法获取std::begin
。
Even if the specialization you want to do is possible (it isn't unless you introduce a member begin()
- an explicit specialization for a function template can't change the return type, and the overload at issue returns "whatever member begin()
returns"; and if you do introduce a member begin()
, why are you specializing std::begin
to do what it would have done anyway?), you still won't be able to use it with a range-based for
. 即使你想要做的特化是可能的(除非你引入一个成员
begin()
否则一个函数模板的显式特化不能改变返回类型,并且有问题的重载返回“无论成员begin()
什么begin()
返回“;而如果你介绍的会员begin()
,你为什么专业std::begin
?做它无论如何都会做),你仍然无法与使用范围为基础的for
。
The right way to add a free function begin
that enables for(:)
loops is to add, in the namespace of stack
, a begin(stack&)
and begin(stack const&)
function that returns a iterator and const_iterator respectively (and ditto for end
) 添加自由函数的正确方法
begin
,使for(:)
循环能够在stack
的命名空间中添加一个begin(stack&)
和begin(stack const&)
函数,它们分别返回一个迭代器和一个const_iterator(和ditto for end
)
The other way is to add a member begin()
and end()
to stack
. 另一种方法是将成员
begin()
和end()
到stack
。
Specializing std::begin
is bad practice for a number of reasons, not the least of which is that not all for(:)
loops will work with it (the lookup rules where changed in the resolution of this defect report ). 专业化
std::begin
是一个不好的做法,原因有很多,其中最重要的是并非所有for(:)
循环都可以使用它(查找规则在此缺陷报告的分辨率中发生了变化)。 Overloading std::begin
is undefined behavior (you may not overload functions in namespace std
under the standard: doing so makes your program ill-formed). 重载
std::begin
是未定义的行为(你可能不会在标准namespace std
重载函数:这样做会使你的程序格式错误)。
This is how it has to be done, even if it violates the naming convention of your project. 即使它违反了项目的命名约定,也必须这样做。
Leaving aside the policy and semantic issues of whether you should specialize a function template from the std
namespace, 撇开是否应该从
std
命名空间专门化函数模板的策略和语义问题,
The following snippet does not work: 以下代码段不起作用:
class stackiterator {};
struct stack { stackiterator Begin() { return stackiterator{};} };
#include <iterator>
namespace std
{
template <> stackiterator begin<stack>(stack& S)
{
return S.Begin();
}
}
However, the following snippet works just fine: 但是,以下代码段工作正常:
class stackiterator {};
struct stack { stackiterator begin() { return stackiterator{};} };
#include <iterator>
namespace std
{
template <> stackiterator begin<stack>(stack& S)
{
return S.begin();
}
}
The key difference is the presence of Begin()
vs begin()
as a member function of stack
. 关键区别在于
Begin()
vs begin()
作为stack
的成员函数。 std::begin()
is defined as: std::begin()
定义为:
template <class C> auto begin(C& c) -> decltype(c.begin());
template <class C> auto begin(const C& c) -> decltype(c.begin());
When you specialize a function template, you must still keep the return type the same. 当您专门化函数模板时,您仍必须保持返回类型相同。 When you don't have
begin()
as a member of Stack
, the compiler does not know how to determine the return type. 当您没有
begin()
作为Stack
的成员时,编译器不知道如何确定返回类型。
That is the reason for error produced by the compiler. 这就是编译器产生错误的原因。
BTW, there is another SO post that partially answers what can be specialized and what can't be specialized. 顺便说一句,还有另一篇SO帖子 ,它部分回答了什么可以是专业的,什么是不专业的。
Looking at the part of the standard that deals with std::begin()
, Section 24.3, I don't see anything about not being able to specialize std::begin()
. 看看处理
std::begin()
的标准部分,第24.3节,我没有看到任何关于无法专门化std::begin()
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.