我在Boost.Range中找到了这个有趣的内容:
提供free-standing functions range_begin/end()
, the docs state that时:
...
range_begin()
和range_end()
必须为const
重载 和mutable
参考参数。
事实上,在end.hpp
中查看默认值时,我们会看到:
//////////////////////////////////////////////////////////////////////
// pair
//////////////////////////////////////////////////////////////////////
template< typename Iterator >
inline Iterator range_end( const std::pair<Iterator,Iterator>& p )
{
return p.second;
}
template< typename Iterator >
inline Iterator range_end( std::pair<Iterator,Iterator>& p )
{
return p.second;
}
你会注意到(并且example given in the docs也这样做)两个版本都返回相同的Iterator
类型。
为什么我们首先需要重载?是否让ADL工作?
答案 0 :(得分:3)
你显然需要const &
版本,否则你的range_begin
对于const限定的对象是不可调用的。
不太明显的是你还需要&
版本,但这很简单:如果你不提供它,那么你的自定义函数比Boost自己的版本更糟糕。
这是一个简短的非Boost示例:
namespace M {
struct S { };
void f(const S &);
}
namespace N {
template <typename T>
void f(T &);
template <typename T>
void g(T &t) { f(t); }
}
void h() {
M::S s {};
N::g(s);
}
此处,在N::g<M::S>
的实例化过程中,会生成一个不合格的电话f(t)
,参数t
的类型为M::S
。有两个候选者:N::f<M::S>
位于同一名称空间中,但ADL也会找到M::f
。前者的参数是M::S &
。后者是const M::S &
。这意味着前者是更好的匹配,即使您真的希望使用名称空间M
中的版本。
额外的重载M::f(S &)
可以避免此问题。