【发布时间】:2015-12-09 05:56:53
【问题描述】:
注意:我已经根据从练习中学到的经验以及此页面上的答案和 cmets 编写了一个“食谱”,请参阅 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 会导致编译错误。我有一些适用于非常量情况的东西:
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; }
非常量情况使用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 时做错了,因为编译器正在寻找非常量 begin()。有没有办法来解决这个问题?
编辑:即使使用简单的 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;
};
【问题讨论】:
-
使用单独的
ConstEnumerationAdaptor调用cbegin和cend可能更容易解决这个问题 -
否则,请尝试将
Container()(在 decltype 内)替换为std::declval<Container&>()(来自) -
其实我觉得问题可能出在
EnumIter<> -
@Schollii 您确实需要
declval中的&,因为您将容器作为左值保存,并且您不想使用错误的类型以防出现右值引用-合格的重载。 -
using iterator_type = std::conditional_t<std::is_const<Container>{}, typename Container::const_iterator, typename Container::iterator>.
标签: c++ templates c++11 iterator constants