为什么对于const和非const引用都重载了Boost.Range range_begin / end自由函数?

时间:2014-03-06 22:09:43

标签: c++ boost overload-resolution argument-dependent-lookup boost-range

我在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工作?

1 个答案:

答案 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 &)可以避免此问题。