1

我发现这个有趣的一点在Boost.Range为什么Boost.Range range_begin/end free函数为const和非const引用都重载?

在提供free-standing functions range_begin/end(), the docs state that

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

你会注意到(和example given in the docs也做到这一点),这两个版本返回相同Iterator类型。

为什么我们首先需要过载?它是否使ADL工作?

回答

3

您显然需要const &版本,否则您的range_begin将不可用于const限定对象。

不太明显的是为什么你还需要&版本,但很简单:如果你不提供它,那么你的自定义函数比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 &)可以避免这个问题。

+0

在你的例子中,'M :: f'是一个非模板函数。这有什么不同(这里)? –

+0

@MartinBa只要'M :: f'同时具有'S&'和'const S&'版本,它就可以工作。为此,这些重载是否由模板提供并不重要。 – hvd

相关问题