2015-11-07 81 views
14

对于std::begin,我们有一个容器两个重载:std :: begin和end的const重载的目的是什么?

template< class C > 
auto begin(C& c) -> decltype(c.begin()); 
template< class C > 
auto begin(const C& c) -> decltype(c.begin()); 

C常量性可以通过平时的模板演绎规则来推断,因此它似乎是第二个重载是多余的。我错过了什么?

回答

9

在rvalue上调用begin(和end)是合理的,只要我们在容器被销毁后不使用生成的迭代器。但是,将右值传递给形式为T&的参数将不起作用,这是第二次超载发挥作用的地方。

但是,它可能是,我们正在处理的前range-based for proposal wording一个轻率的改造:

添加以下的[container.concepts.member]结束:

template<Container C> concept_map Range<C> { 
    typedef C::iterator iterator; 
    iterator begin(C& c) { return Container<C>::begin(c); } 
    iterator end(C& c) { return Container<C>::end(c); } }; 

template<Container C> concept_map Range<const C> { 
    typedef C::const_iterator iterator; 
    iterator begin(const C& c) { return Container<C>::begin(c); } 
    iterator end(const C& c) { return Container<C>::end(c); } }; 

当清楚概念不会变成C++ 11时,论文被修改了,并且所有四个函数temploids可能被翻译成等价的命名空间s应付功能模板。这会导致rvalues被接受(可能是非预期的)后果,而原始代码只是为了区分不同限定的容器类型。

请注意,现代实现的begin/end将使用转发引用 - 例如,

template <typename T> 
constexpr auto begin(T&& t) 
    -> decltype(std::forward<T>(t).begin()) { 
    return std::forward<T>(t).begin(); 
} 
+1

我并不确信这是故意设计。从容器中获取'begin()'而不能从同一个容器中获得'end()'看起来并不有用。 –

+0

@ T.C。 ......除非你知道它的长度的上限。无论如何,我试图追查这篇论文。 – Columbo

+2

当然,除了数组rvalues没有重载,它的长度实际上是在类型中,所以在调用站点中肯定是已知的。就我个人而言,我怀疑它是适应旧的[容器概念图]的一件神器(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2778.htm#container-concept- maps-container-concepts-member),它们分别使用'const_iterator'和'iterator'分别具有'const'和'nonconcon'版本。 –