1

Boost.Rangeでこの興味深いビットを見つけました:

独立した関数range_begin/end()を提供する場合、ドキュメントには次のように記載されています。

...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;
    }

両方のバージョンが同じ型を返すことに注意してください (ドキュメントに示されている例もこれを行っています)。Iterator

そもそもなぜ両方のオーバーロードが必要なのでしょうか? ADLを機能させるためですか?

4

1 に答える 1

3

そうしないと、const修飾されたオブジェクトに対して呼び出すことができconst &ないため、明らかにバージョンが必要です。range_begin

バージョンも必要な理由はあまり明白ではあり&ませんが、単純です。それを提供しない場合、カスタム関数は 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です。候補は 2 つあります。N::f<M::S>は同じ名前空間にありますが、ADL は も検出しM::fます。前者のパラメータはM::S &です。後者はconst M::S &. つまり、本当に名前空間のバージョンをM使用したい場合でも、前者の方が適しているということです。

オーバーロードを追加するM::f(S &)と、この問題が回避されます。

于 2014-03-06T22:38:36.690 に答える