I have a class A and it has an STL container as a member. I also have a class A_Iterator which provides functionality to iterate over the member variable within A, in different ways. When I want to use this iterator , I do something like
main(){
A a;
A_Iterator iter(a);
do{
// do some stuff;
} while (iter++);
}
For the while loop to exit, I am having to provide a conversion function within A_Iterator of the form operator void*(). Within this function, based on some other logic, I return (void*) this or NULL based on whether there are more elements to visit or the end has been reached.
My question is that, I looked up this way of implementing the end condition from some place online. I am not able to understand why while (iter) would invoke the operator void * conversion function.
Can anyone please explain how this works.
Thanks
KarthikR

When is operator void* invoked.
zemien
> Conditional-expressions inside conditional statements, such as while, are type int.
They are of type bool indeed.
> Through a rather elaborate set of type conversion rules, it ends up picking
> the void* cast operator that you defined, since void* is convertable to int.
Of course it is not. Void* is not convertible to int. It is allowed with reinterpret_cast only.
--
Michael Kochetkov
MrKnudsen
I am new to VC++. So I cant comment on Michael's claims.
But as far as using a hidden object to return for the post increment case (as suggested by Jensen), it seems like there is still a problem.
When I do something like
do{
..
}while(iter++)
and I have
operator++(int){
A_Iterator a_iter = *this;
// steps for incrementing this
return a_iter;
}
it still doesnt work because, the condition for checking whether the iterator is at the end is within opertaor void*(). I guess I will have to move this check into the operator++(int) method in which case I wont require operator void*().
KarthikR
Tommi Enenkel
And to take that one step further, using the post-increment operator causes more work to be done, as the operator is still called before evaluation but since the pre-incremented value is being evaluated, the iterator has to make a copy of itself to return before it increments itself. And that copy, of course, has to be destroyed after each iteration.
JeroGrav
I'll take this one. Conditional-expressions inside conditional statements, such as while, are type int. The expression iter++ is type Iterator_A& (all objects evaluate to themselves, the post-incrementing is a side effect that does not affect the type of the expression). The compiler then needs find a way to convert Iterator_A& to int. Through a rather elaborate set of type conversion rules, it ends up picking the void* cast operator that you defined, since void* is convertable to int.
This is a double conversion, which is why I had raised my concern about relying on implicit conversions. But in actuality, my suggestion of using iter != 0 is no better. It goes through the same conversion resolution in the compiler. I had originally wanted to suggest !iter.done() instead, but I realized that C++ was meant to be used this way.
Jensen makes an excellent point about the hidden copy of the Iterator_A object in order to mimic the post-increment. In VC8, my code produced a compiler diagnostic to warn me about this (although it could have been more informative as to why the diagnostic is being given). Perhaps you're using an earlier compiler where this diagnostic was not built into the compiler.
Brian
Denis A.B.
That is true. I guess I'll just go with the prefix version. But I guess a part of my question is still unanswered. How and when does that operator void*() get called when executing while (iter++). Can you explain this Jensen
Thanks
KarthikR
meoryou
> My question is that, I looked up this way of implementing the end condition from
> some place online. I am not able to understand why while (iter) would invoke the
> operator void * conversion function.
> Can anyone please explain how this works.
First of all I believe you would better ask such general C++ how-to questions in places like comp.lang.c++ -- you will get the quick, helpful and absolutely exact result. While this forum is more likely about C++ implementation from MS.
I read your question as you do not know why on earth people use operator void* instead of operator bool or int in logical expressions. That is because a C++ can implicitly convert them into values of some other types and use the resulting values in arithmetic operations, choosing overloaded functions, etc. That is not you generally want -- you want to have an indication that would participate in logical expressions only. The void* is the best choice -- it is almost good for nothing other then to be compared with the special kind of literal '0'. That is exactly what happens in you very case. As you already know it cannot be compared to 1,2 or any other integral value because void* is not convertible to them. '0' is the kind of exception and you may treat it as a special (really missing) keyword Null, nill, nul, etc. But again I believe any decent book on C++ shall explain it much better then you could expect it here.
--
Michael Kochetkov
newX
Thanks Brian and Jensen for your replies.
Brian,
The iterator class I am writing is a bit different from the STL iterator code. The container that I have within class A actually stores a set of words with different properties like a word can be "all caps" or a word can be "only digits" or "only alphabets" and so on. I intend have an struct that stores these categories and I intend to pass this struct to my iterator so that I can iterate through the container visiting only the words that I want (for example, visiting only "all caps" etc). This is why I am writing an iterator instead of using the STL code.
I agree with your point that while (iter) could be replaced by the for loop you have suggested.
I did not get a compiler warning when I implemented the iter++ as I mentioned above.
You mentioned about the iterator being null within the loop. I understand but is there a better way to implement the postfix operator
Jensen,
I understand your point but is there a better way to implement the postfix opertaor without creating a copy and returning the copy. (Or are you suggesting that I should not use a postfix increment and should use a prefix increment instead.)
Thanks,
KarthikR
JJSingh
I think the question itself is indicative that you might be going down the wrong path. Not only are you trying to fake polymorphism with void* (something one might do in C but is completely unnecessary in C++), you're also trying to rely on implicit conversion operators for important functionality.
0. Make sure you're not reinventing the wheel by writing iterator code that STL already provides.
1. you are post-incrementing iter, meaning that you're using the state of iter prior to be incremented as the exit condition. So when iter takes on the NULL state, you're inside the loop body.
2. iter might be in a NULL state before you enter the loop.
3. iter++ generates a C4620 warning. So we should try using ++iter;
4. For readability purposes you should consider being more explicit on measuring the state for the exit condition. Although while( iter ) is brief, it's also a bit obfuscated.
With 1-4 in mind, you could rewrite the loop as as:
for( A_Iterator iter(a); iter != 0; ++iter )
{
}
But to take this further, I suspect that your code would be more solid if you used templates. Here's an example of what you could do.
template
<class ContainerType, class ItemType>class MyIterator
{
public:
MyIterator( ContainerType& _container )
: container( _container )
{
} operator ItemType*()
{
// get the item from the container, assumed to be type ItemType*
// (don't cast to it--let the compiler typecheck it)
// Return 0 for now
return 0;
} void operator++()
{
// do increment logic
}
private
:ContainerType& container;
};
class
A // pretend type{
};
int
main(){
A a; // pretend A is a container of type int for( MyIterator<A,int> iter(a); iter != 0; ++iter )
{
}
}
LandLord323
It's a better practice to use the pre-increment operator. You can implement you post-increment operator to not make a copy, but then it's essentially a pre-increment operator masquareding as a post-increment operator.