1

我在Boost.Range中发现了这个有趣的部分:

在提供独立功能range_begin/end()时,文档声明

...range_begin()并且range_end()必须为两个constmutable引用参数重载。

事实上,查看它们在 中的默认值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;
    }

您会注意到(文档中给出的示例也这样做)两个版本都返回相同的Iterator类型。

为什么我们首先需要两个重载?是为了让ADL工作吗?

4

1 回答 1

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 &)可以避免这个问题。

于 2014-03-06T22:38:36.690 回答