C++ 如何专门化std::begin?

C++ 如何专门化std::begin?,c++,templates,c++11,template-specialization,template-function,C++,Templates,C++11,Template Specialization,Template Function,我正在尝试为自定义容器专门化std::begin。我这样做是因为我想对容器使用基于范围的。这就是我所拥有的: class stackiterator { … }; class stack { … }; #include <iterator> template <> stackiterator std::begin(stack& S) { return S.GetBottom(); } 类堆栈迭代器{…}; 类堆栈{…}; #包括 模板堆栈迭代器std::

我正在尝试为自定义容器专门化
std::begin
。我这样做是因为我想对容器使用基于范围的
。这就是我所拥有的:

class stackiterator { … };
class stack { … };

#include <iterator>

template <> stackiterator std::begin(stack& S)
{
  return S.GetBottom();
}
类堆栈迭代器{…};
类堆栈{…};
#包括
模板堆栈迭代器std::begin(堆栈&S)
{
返回S.GetBottom();
}
我在定义我的
begin
专业化时遇到以下错误:

没有与函数模板专用化“开始”匹配的函数模板

我做错了什么

我正在尝试为自定义容器专门化
std::begin
。我是 这样做是因为我想对容器使用基于范围的

你找错人了。基于范围的
for
根本不使用
std::begin
。对于类类型,编译器直接查找成员
begin
end
,如果两者均未找到,则仅在相关名称空间中进行ADL查找,查找免费
begin
end
。不执行普通的非限定查找;如果您的类不在
std
命名空间中,则无法拾取
std::begin


即使您想要进行的专门化是可能的(除非您引入了一个成员
begin()
——函数模板的显式专门化不能更改返回类型,并且出现问题的重载返回“which member
begin()
returns”;如果您引入了一个成员
begin())
,你为什么要专门使用
std::begin
来做它本来可以做的事情呢?),你仍然无法将它与基于范围的
for
一起使用,添加免费函数
begin
的正确方法是为(:)
循环启用
stack
的命名空间中添加
begin(stack&)
开始(堆栈常量&)
函数,分别返回迭代器和常量迭代器(对于
结束
,同上)

另一种方法是将成员
begin()
end()
添加到
stack

专门化
std::begin
是一种不好的做法,原因有很多,尤其是(:)
循环的
并非都能与之配合使用(查找规则发生了更改)。重载
std::begin
是未定义的行为(根据标准,您不能重载
命名空间std
中的函数:这样做会导致程序格式错误)


这就是必须这样做的,即使它违反了项目的命名约定。

抛开是否应该从
std
命名空间专门化函数模板的策略和语义问题

以下代码段不起作用:

class stackiterator {};
struct stack { stackiterator Begin() { return stackiterator{};} };

#include <iterator>

namespace std
{
   template <> stackiterator begin<stack>(stack& S)
   {
      return S.Begin();
   }
}
专门化函数模板时,必须保持返回类型不变。当您没有
begin()
作为
Stack
的成员时,编译器不知道如何确定返回类型

这就是编译器产生错误的原因

顺便说一句,这部分回答了什么可以专业化,什么不能专业化


查看标准中涉及
std::begin()
,第24.3节的部分,我看不出不能专门化
std::begin()

为堆栈类创建一个begin成员函数,该函数返回迭代器,并且不需要模板专门化。为什么不实现
stack::begin())
只需按原样使用
std::begin()
as is?@RSahu的实现,因为项目的命名约定对函数使用PascalCase。@zenith,这样您就可以通过ADL找到其他
begin
函数。它很混乱,Eric Niebler提出了一个解决方案,使
std::begin
(和其他定制点)这样做,我们就不会在函数顶部出现重复的using语句,这些语句会随着自定义点列表的增加而变大。我认为标准优先于编码约定。。。您应该仔细检查是否编写了一个成员begin函数。那么,当它说可以通过专门化
std::begin
来实现基于范围的
兼容性时,这意味着什么呢?这是错误的吗?@zenith它已经过时了。请注意,它应该是标准允许的
std::begin
(不是重载)的专门化。如果您已经有一个成员
begin()
,那么您到底为什么要专门化
std::begin()
?@TC,这是对我的评论还是对OP的评论?
class stackiterator {};
struct stack { stackiterator begin() { return stackiterator{};} };

#include <iterator>

namespace std
{
   template <> stackiterator begin<stack>(stack& S)
   {
      return S.begin();
   }
}
template <class C> auto begin(C& c) -> decltype(c.begin());
template <class C> auto begin(const C& c) -> decltype(c.begin());