如何专门化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
专门化的定义:
没有函数模板匹配函数模板特化'begin'
我做错了什么?
你找错对象了。基于范围的我试图将
std::begin
专门用于定制容器。我这样做是因为我想使用基于范围的for
与容器。
for
根本不使用std::begin
。对于类类型,编译器直接查找成员begin
和end
,如果都没有找到,则在关联的名称空间中查找空闲的begin
和end
。不执行普通的非限定查找;如果您的类不在std
名称空间中,则无法拾取std::begin
。即使你想要做的特化是可能的(除非你引入了成员begin()
——函数模板的显式特化不能改变返回类型,并且有问题的重载返回"任何成员begin()
返回";如果你确实引入了成员begin()
,为什么你要专门化std::begin
来做它本来可以做的事情呢?),你仍然不能将它与基于范围的for
一起使用。
不考虑是否应该专门化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()
和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()
的任何内容。
添加一个允许for(:)
循环的自由函数begin
的正确方法是在stack
的命名空间中添加一个begin(stack&)
和begin(stack const&)
函数,分别返回一个迭代器和一个const_iterator (end
也是如此)
另一种方法是给stack
增加成员begin()
和end()
。
专门化std::begin
是一个不好的实践,原因有很多,其中最重要的是,并不是所有的for(:)
循环都可以使用它(查找规则在这个缺陷报告的解析中被改变了)。重载std::begin
是一种未定义的行为(你不能在标准下重载namespace std
中的函数:这样做会使你的程序形式不良)。
必须这样做,即使它违反了项目的命名约定。
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- std::map<struct,struct>::find 找不到匹配项,但是如果我循环通过 begin() 到 end(),我在那里看到匹配项
- 为constchar*定义std::begin合法吗
- constexpr begin of a std::array
- std::ranges::begin 和 std::begin 有什么区别?
- 为什么 std::find( s.begin(), s.end(), val ) 比集合 s 的 s.find(val) 慢 1000 倍<int>?
- 递减 std::vector::begin 是否未定义,即使它从未被使用过?
- std::begin-类型特征中未考虑用户定义的重载
- 当从成员类调用封装的std::begin时,程序崩溃
- C++ - 空的 std::list begin() 和 end() 不相等
- 为什么std::begin()和std::end()适用于固定数组,而不适用于动态数组
- C++代码"x.erase(std::remove(x.begin(), x.end(), ), x.end())"是如何工作的?
- 重载 std::begin() 和 std::end() 用于非数组
- 使用 std::set 的 .begin() 和 .end() 函数会产生意想不到的结果
- 为什么 free 函数不能在 C 数组上运行,而 std::begin 在某些情况下可以在 C++14 中运行?
- std::begin() 和 std::end() 不适用于类中的未知长度数组
- 在 std::list 中,std::d istance(it.begin(), std::p rev(it.end()
- 为什么在 std::vector 擦除中需要 begin()
- 将模式包装为 std::begin; 返回 begin(c); 到函数中
- 为什么在这种情况下"std::begin()"总是返回"const_iterator"?