template <class Enum>
class EnumIterator {
public:
const Enum* operator-> () const {
return &(Enum::OfInt(i)); // warning: taking address of temporary
}
const Enum operator* () const {
return Enum::OfInt(i); // There is no problem with this one!
}
private:
int i;
};
我上面得到了这个警告。目前我正在使用这个黑客:
template <class Enum>
class EnumIterator {
public:
const Enum* operator-> () {
tmp = Enum::OfInt(i);
return &tmp;
}
private:
int i;
Enum tmp;
};
但这很难看,因为迭代器是一个缺失的容器。
迭代值范围的正确方法是什么?
更新 迭代器专门用于支持命名静态构造函数OfInt(更新代码片段)的特定集合对象。
请不要挑选我粘贴的代码,但只是要求澄清。我试图提取一个简单的部分。
如果你想知道T将是强enum类型(基本上是一个int打包成一个类)。会有typedef EnumIterator&lt; EnumX&gt;迭代器;内部类EnumX。
更新2: 添加的consts表示将通过 - &gt;访问的强枚举类的成员不要更改返回的临时枚举。
使用operator *更新了代码,没有任何问题。
答案 0 :(得分:1)
有很多种迭代器。
例如,在向量上,迭代器通常是普通指针:
template <class T>
class Iterator
{
public:
T* operator->() { return m_pointer; }
private:
T* m_pointer;
};
但这是有效的,因为矢量实际上只是一个数组。
在双向链表上,它会有所不同,列表将由节点组成。
template <class T>
struct Node
{
Node* m_prev;
Node* m_next;
T m_value;
};
template <class T>
class Iterator
{
public:
T* operator->() { return m_node->m_value; }
private:
Node<T>* m_node;
};
通常,您希望迭代器尽可能轻,因为它们是按值传递的,因此指向底层容器的指针是有意义的。
您可能希望添加额外的调试功能:
但这些都是细节,首先,这有点复杂。
另请注意Boost.Iterator,这有助于锅炉板代码。
编辑:(更新1和2分组)
在你的情况下,如果你的迭代器只是一个int,你就不需要更多了。实际上对于你强大的枚举你甚至不需要迭代器,你只需要operator ++和operator--:)
引用容器通常是为了实现那些++和 - 运算符。但是从你的元素中,只需要一个int(假设它足够大),并且获得前一个和下一个值的方法就足够了。
虽然如果你有一个静态向量,那么你可以简单地重用一个向量迭代器。
答案 1 :(得分:1)
Enum* operator-> () {
tmp = Enum::OfInt(i);
return &tmp;
}
问题不在于它的丑陋,而在于它不安全。会发生什么,例如在以下代码中:
void f(EnumIterator it)
{
g(*it, *it);
}
现在g()
最终得到两个指针,这两个指针指向同一个内部临时指针,它应该是迭代器的实现细节。如果g()
通过一个指针写入,则另一个值也会改变。哎哟。
你的问题是,这个函数应该返回一个指针,但你没有指向的对象。无论如何,你都必须解决这个问题。
我看到两种可能性:
enum
,并且枚举类型没有成员,所以operator->
无论如何都是无用的(除非被调用,否则它不会被实例化,因为它不会被调用导致编译时错误)并且可以安全地省略。 Enum::enum_type
)存储在迭代器中,并且仅当您要执行整数时才将其强制转换为int
。它上面的操作(例如,增量)。 答案 2 :(得分:0)
迭代器迭代特定容器。实现取决于它是什么类型的容器。您返回的指针应指向该容器的成员。您不需要复制它,但是您需要跟踪您正在迭代的容器,以及您所处的位置(例如,向量的索引),可能是在迭代器的构造函数中初始化的。或者只使用STL。
答案 3 :(得分:0)
OfInt返回什么?在这种情况下,它似乎返回了错误的类型。它应该返回一个T *而不是它似乎返回一个T值,然后你取的是地址。这可能会产生不正确的行为,因为它会丢失通过 - &gt;。
进行的任何更新答案 4 :(得分:0)
因为没有容器我决定将迭代器合并到我强大的Enum中。 我将raw int设置为-1以支持空枚举(limit == 0)并且能够使用TryInc的常规for循环。
以下是代码:
template <uint limit>
class Enum {
public:
static const uint kLimit = limit;
Enum () : raw (-1) {
}
bool TryInc () {
if (raw+1 < kLimit) {
raw += 1;
return true;
}
return false;
}
uint GetRaw() const {
return raw;
}
void SetRaw (uint raw) {
this->raw = raw;
}
static Enum OfRaw (uint raw) {
return Enum (raw);
}
bool operator == (const Enum& other) const {
return this->raw == other.raw;
}
bool operator != (const Enum& other) const {
return this->raw != other.raw;
}
protected:
explicit Enum (uint raw) : raw (raw) {
}
private:
uint raw;
};
用法:
class Color : public Enum <10> {
public:
static const Color red;
// constructors should be automatically forwarded ...
Color () : Enum<10> () {
}
private:
Color (uint raw) : Enum<10> (raw) {
}
};
const Color Color::red = Color(0);
int main() {
Color red = Color::red;
for (Color c; c.TryInc();) {
std::cout << c.GetRaw() << std::endl;
}
}