const迭代器的模板形参,而不是迭代器

template parameter for const iterator instead of iterator

本文关键字:迭代器 const 形参      更新时间:2023-10-16

:我根据从练习中得到的教训和答案写了一个"配方" & &;关于本页的评论,请参阅http://www.codeproject.com/Tips/1029941/Python-like-enumeration-in-Cplusplus。

我正在摆弄c++ 11给c++ 03带来的扩展。我希望能够使用以下代码迭代容器:

int main()
{
    std::list<int> list = { 1, 2, 3, 4, 5, 6, 7 };
    for (auto x : enumerated(list))
        cout << x.first << " " << x.second << endl;
    for (auto x : const_enumerated(list))
        cout << x.first << " " << x.second << endl;
}

第一次迭代的x是可修改的,而对于第二次迭代,试图修改x将导致编译错误。我有一些适用于非const情况的东西:

template <typename Container>
class EnumerationAdaptor
{
public:
    EnumerationAdaptor(Container& container) : container_(container) {}
    EnumIter<typename Container::iterator> begin() const { return container_.begin(); }
    EnumIter<typename Container::iterator> end() const { return container_.end(); }
private:
    Container& container_;
};
template <typename Container>
EnumerationAdaptor<Container> enumerated(Container& container) { return container; }
template <typename Container>
EnumerationAdaptor<const Container> const_enumerated(const Container& container) { return container; }

非const情况使用EnumIter<std::list<...>::iterator>,根据需要,我试图使const情况使用EnumIter<std::list<...>::const_iterator>作为begin()end()的返回类型。似乎我需要decltype:

template <typename Container>
class EnumerationAdaptor
{
public:
    EnumerationAdaptor(Container& container) : container_(container) {}
    EnumIter<decltype(Container().begin())> begin() const { return container_.begin(); }
    EnumIter<decltype(Container().end())> end() const { return container_.end(); }  // *** compile error (see below)
private:
    Container& container_;
};

但我得到一个编译错误在Visual Studio 2015 Express:

Error   C2440   'return': cannot convert from 
'std::_List_const_iterator<std::_List_val<std::_List_simple_types<int>>>' 
to  
 'EnumIter<std::_List_iterator<std::_List_val<std::_List_simple_types<int>>>>'
[in c:users...enumeratedcpp.cpp line 46, which is line marked ***]

,这表明我做了一些错误的decltype,因为编译器正在寻找非const begin()。有办法解决这个问题吗?

EDIT:即使使用简单的EnumIter,问题也是一样的:

template <typename Iter>
class EnumIter
{
public:
    EnumIter(Iter begin) : iter_(begin) {}
    EnumIter& operator++()
    {
        return *this;
    }
    bool operator!=(const EnumIter& rhs)
    {
        return iter_ != rhs.iter_; // or self.index_ != rhs.index_;
    }
    int operator*() const
    {
        return index_;
    }
private:
    Iter iter_;
    int index_ = 0;
};

这个表达式有一个问题:

decltype(Container().begin())

Container()仅在Container恰好是默认可构造的情况下才起作用。这毫无理由地限制了类的可用性。(还有一个较小的问题,这对原始数组不起作用,但这是另一个练习)。

除此之外,代码对于类类型是完全有效的。从[expr.type.conv]:

表达式T(),其中T是非数组完整对象的简单类型说明符或类型名称说明符类型或(可能是cv限定的)void类型,创建指定类型的右值[…]

如果Containerconst list<int>,那么整个表达式的类型应该是list<int>::const_iterator。如果MSVC给了你其他的东西,那就是一个bug。

也就是说,我们确实应该解决违约可构造性问题。这就是std::declval的用武之地:

decltype(std::declval<Container&>().begin())

这不会对Container施加任何限制,也许MSVC会正确处理这个问题。