const迭代器的模板参数而不是迭代器

时间:2015-09-12 22:24:37

标签: c++ templates c++11 iterator const

注意 :我写了一个"配方"根据从练习中获得的经验教训和答案&有关此页面的评论,请参阅http://www.codeproject.com/Tips/1029941/Python-like-enumeration-in-Cplusplus

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

$server=1

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

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

非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>作为EnumIter<std::list<...>::const_iterator>和{{1}的返回类型}。好像我需要decltype:

begin()

但是我在Visual Studio 2015 Express中遇到了编译错误:

end()

这表明我对decltype做错了,因为编译器发现了非const的begin()。有没有办法来解决这个问题?

编辑:即使使用简单的EnumIter,问题也是如此:

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

1 个答案:

答案 0 :(得分:2)

此表达式存在一个问题:

decltype(Container().begin())

Container()仅在Container碰巧是默认构造时才有效。这无异于限制了你班级的可用性。 (有一个较小的问题是,这对原始阵列不起作用,但这是另一项练习)。

除此之外,代码对类类型完全有效。来自[expr.type.conv]:

  

表达式T(),其中T是非数组完整对象的simple-type-specifier或typename-specifier   type或(可能是cv-qualified)void类型,创建指定类型[...]

的prvalue

因此,如果Containerconst list<int>,则整个表达式的类型应为list<int>::const_iterator。如果MSVC给你一些其他的东西,这就是一个错误。

那就是说,我们真的应该解决默认构造问题。那是std::declval的来源:

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

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