views:

68

answers:

1

I have a linked list structure:

struct SomeLinkedList
{
    const char* bar;
    int lots_of_interesting_stuff_in_here;
    DWORD foo;
    SomeLinkedList* pNext;
};

It is part of an existing API and I cannot change it.

I would like to add iterator support. The boost::iterator_facade<> library seemed ideal for the purpose.

class SomeIterator
    : public boost::iterator_facade< SomeIterator, 
                                     const SomeLinkedList, 
                                     boost::forward_traversal_tag >
{
public:
    SomeIterator() : node_( NULL ) {};

    explicit SomeIterator( const SomeLinkedList* p ) : node_( p ) {};

private:
    friend class boost::iterator_core_access;

    void increment() { node_ = node_->pNext; };

    bool equal( SomeIterator const& other ) const { /*some comparison*/; };

    SomeLinkedList const& dereference() const { return *node_; };

    SomeLinkedList const* node_;
}; // class SomeIterator

The goal is to be able to use it in standard library functions like std::for_each

void DoSomething( const SomeLinkedList* node );

SomeLinkedList* my_list = CreateLinkedList();
std::for_each( SomeIterator( my_list ), SomeIterator(), DoSomething );

Unfortunately, I'm getting an error saying it's trying to pass the list by value rather than by pointer.

error C2664: 'void (const SomeLinkedList *)' : cannot convert parameter 1 from 'const SomeLinkedList' to 'const SomeLinkedList *'

How can I change SomeIterator to do to get this working correctly?

Thanks, PaulH


Edit: I've tried this:

class SomeIterator
    : public boost::iterator_facade< SomeIterator, 
                                     SomeLinkedList, 
                                     boost::forward_traversal_tag,
                                     SomeLinkedList* >
{
    // ...

but I get this complier error:

error C2664: 'boost::implicit_cast' : cannot convert parameter 1 from 'SomeLinkedList **' to 'boost::detail::operator_arrow_proxy<T>

Edit 2:

I've tried modifying the dereference type:

class SomeIterator
    : public boost::iterator_facade< SomeIterator, 
                                     const SomeLinkedList, 
                                     boost::forward_traversal_tag >
{
    // ...

    const SomeLinkedList* dereference() const { return node_; };

but, I get the original error:

error C2664: 'void (const SomeLinkedList *)' : cannot convert parameter 1 from 'const SomeLinkedList' to 'const SomeLinkedList *'
+1  A: 

When your iterator is dereferenced, it would return a const SomeLinkedList& however your DoSomething function is expecting a const SomeLinkedList*. Either alter the iterator to somehow return pointers when dereferenced or alter your DoSomething function.


EDIT in response to further discussion:

I haven't actually used boost::iterator_facade myself, but looking at additional code you posted it appears you might not have changed all the necessary parts at the same time.

Have you actually tried

class SomeIterator
    : public boost::iterator_facade< SomeIterator, 
                                     SomeLinkedList, 
                                     boost::forward_traversal_tag,
                                     SomeLinkedList* >
{

and

const SomeLinkedList* dereference() const { return node_; };

together?

Or if that doesn't work, then how about:

class SomeIterator
    : public boost::iterator_facade< SomeIterator, 
                                     SomeLinkedList*, 
                                     boost::forward_traversal_tag>
{

const SomeLinkedList* dereference() const { return node_; };

Alternatively, as davka suggested in a comment, what about solving the pointer vs reference issue by making a wrapper around DoSomething? Such as:

void DoSomethingWrapper( const SomeLinkedList& node )
{
    DoSomething(&node);
}

In fact, you could probably even keep the wrapper the same name as the function it wraps and just let overloading rules take care of when the pointer or reference version gets called.

TheUndeadFish
`DoSomething` is also fixed and cannot be changed. I'd like to know how to modify the `boost::iterator_facade<>` object to work. Ideally, it would behave just like `std::vector< SomeLinkedList* >::const_iterator` (but forward traversal only)
PaulH
@PaulH: So did you at least try to change what the iterator dereferences to (also don't forget the template parameters)? IMO, this thing won't look much like regular stdlib iterators, unless it dereferences to the DWORD member anyway. For example, if I want to use `std::find` to find a node with a specific value, why should this not work? Why should the iteration details (that it is a node in an intrusive linked list) get in the way?
UncleBens
@UncleBens - The idea here is that I **could** use algorithms like `std::find`. Yes, I've tried several things to change what the iterator dereferences to. As yet, I've been unsuccessful in doing that within the framework of `boost::iterator_facade<>`. That is, essentially, what I'm asking in this question.
PaulH
davka