如何专精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
专业化的定义中遇到以下错误:
No function template matches function template specialization 'begin'
我做错了什么?
I'm trying to specialize std::begin
for a custom container. I'm
doing this because I want to use range-based for
with the container.
你找错人了。基于范围的 for
根本不使用 std::begin
。对于 class 类型,编译器直接查找成员 begin
和 end
,如果两者都没有找到,则对 begin
和 [=15= 进行仅 ADL 查找] 在关联的命名空间中。不执行普通的不合格查找;如果您的 class 不在 std
命名空间中,则无法获取 std::begin
。
即使你想做的特化是可能的(除非你引入一个成员 begin()
- 函数模板的显式特化不能改变 return 类型,以及有问题的超载 returns "whatever member begin()
returns";如果你确实引入了一个成员 begin()
,你为什么要专门化 std::begin
去做它本来会做的事情?),您仍然无法将它与基于范围的 for
.
一起使用
添加启用 for(:)
循环的自由函数 begin
的正确方法是在 stack
的命名空间中添加 begin(stack&)
和 begin(stack const&)
函数 returns 一个迭代器和 const_iterator 分别(end
也是如此)
另一种方法是在stack
.
中添加成员begin()
和end()
出于多种原因,专门化 std::begin
是一种不好的做法,其中最重要的是并非所有 for(:)
循环都可以使用它(更改的查找规则 in the resolution of this defect report ).重载 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()
与 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());
当你专门化一个函数模板时,你必须仍然保持 return 类型相同。当你没有 begin()
作为 Stack
的成员时,编译器不知道如何确定 return 类型。
这就是编译器产生错误的原因。
顺便说一句,another SO post 部分回答了哪些可以专门化,哪些不能专门化。
查看标准中涉及 std::begin()
的部分,第 24.3 节,我没有看到任何关于无法专门化 std::begin()
.
的内容
我正在尝试 std::begin
专门用于自定义容器。我这样做是因为我想对容器使用基于范围的 for
。这是我的:
class stackiterator { … };
class stack { … };
#include <iterator>
template <> stackiterator std::begin(stack& S)
{
return S.GetBottom();
}
我在 begin
专业化的定义中遇到以下错误:
No function template matches function template specialization 'begin'
我做错了什么?
I'm trying to specialize
std::begin
for a custom container. I'm doing this because I want to use range-basedfor
with the container.
你找错人了。基于范围的 for
根本不使用 std::begin
。对于 class 类型,编译器直接查找成员 begin
和 end
,如果两者都没有找到,则对 begin
和 [=15= 进行仅 ADL 查找] 在关联的命名空间中。不执行普通的不合格查找;如果您的 class 不在 std
命名空间中,则无法获取 std::begin
。
即使你想做的特化是可能的(除非你引入一个成员 begin()
- 函数模板的显式特化不能改变 return 类型,以及有问题的超载 returns "whatever member begin()
returns";如果你确实引入了一个成员 begin()
,你为什么要专门化 std::begin
去做它本来会做的事情?),您仍然无法将它与基于范围的 for
.
添加启用 for(:)
循环的自由函数 begin
的正确方法是在 stack
的命名空间中添加 begin(stack&)
和 begin(stack const&)
函数 returns 一个迭代器和 const_iterator 分别(end
也是如此)
另一种方法是在stack
.
begin()
和end()
出于多种原因,专门化 std::begin
是一种不好的做法,其中最重要的是并非所有 for(:)
循环都可以使用它(更改的查找规则 in the resolution of this defect report ).重载 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()
与 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());
当你专门化一个函数模板时,你必须仍然保持 return 类型相同。当你没有 begin()
作为 Stack
的成员时,编译器不知道如何确定 return 类型。
这就是编译器产生错误的原因。
顺便说一句,another SO post 部分回答了哪些可以专门化,哪些不能专门化。
查看标准中涉及 std::begin()
的部分,第 24.3 节,我没有看到任何关于无法专门化 std::begin()
.