1

Hello I have following code.

typedef struct __vector {
       int (*container_end) ( struct __vector *);
}vector;

and another iterator structure with following declaration :

typedef struct __iterator {      
    void *ptr_to_container;  
    int (*end)(struct __iterator *);
}iterator;                          

int                                 
end(iterator *itr) {                
    return (itr->ptr_to_container)->container_end(itr->ptr_to_container);
}       

This code does not compile as ptr_to_container is void pointer.

Is there any work-around to this problem.

container_end function will be defined separately and ptr_to_container will point to some container.

thanks Avinash

Avinash
  • 12,851
  • 32
  • 116
  • 186
  • Have you tried casting itr->ptr_to_container to `__vector*`? – Patrick R. Feb 14 '11 at 12:26
  • 1
    [__vector as an identifier is undefined behaviour](http://stackoverflow.com/questions/224397/why-do-people-use-double-underscore-so-much-in-c) and I know of several compilers which will actually choke on this too. [see also](http://c-faq.com/decl/namespace.html) – Flexo Feb 14 '11 at 12:38
  • You're trying to achieve static (i.e. compile-time) polymorphism; this is essentially impossible in C (without some sort of separate code-generation phase). – Oliver Charlesworth Feb 14 '11 at 12:41
  • I want this code to be used by other containers so cannot typecast to specific type. Since you talk about separate code-generation, I think I have to go with MACRO based code. – Avinash Feb 14 '11 at 13:00
  • Are you sure that the function pointer defined in `iterator` really should take an iterator structure as argument? It it took the container as a pointer, you could get this to work with fairly clean C code. – Christoffer Feb 14 '11 at 13:19

4 Answers4

2

It looks like you have missed something when defining the iterator structure. Why does the iterator have a function pointer to an 'end' function that accepts an iterator?

If you want it to be really generic, you could perhaps use this definition instead:

typedef struct __iterator {
    void * ptr_to_container;
    int (*end)(void *);
} iterator;

int end(iterator * it) { return it->end(it->ptr_to_container)); }

In the vector definition (and other data types), you can then define a function to create an iterator:

static int vector_end(vector * v) { /* implementation omittted */ }

iterator * vector_create_iterator(vector * v)
{
    iterator * it = malloc(sizeof(iterator));
    it->ptr_to_container = v;
    it->end = vector_end;
    return it;
}

However, the solution really depends on how the data structures are defined. In the above suggestion, it is up to each data structure to provide an implementation for how to traverse it.

As an alternative, you could set up a generic data structure interface, like

typedef struct _container container;

struct _container {
    int (*end)(container * c);
};

Then the vector implementation would "only" have to fill in this container structure:

typedef struct _vector {
    container c;
    /* other fields required by the vector */
}

static int vector_end(container * c)
{
    vector * v = (vector *) c;
    ...
} 

container * create_vector()
{
    vector * v = malloc(sizeof(vector));
    v->c.end = vector_end;
    return v;
}

...and the iterator could work with just the generic container:

typedef struct _iterator {
    container * c; 
    /* other fields used by the iterator, such as current position */
}

int end(iterator * it) { return it->c->end(it->c); }

From the code sample in the question, it looks almost like you have mixed up these two approaches :-)

Christoffer
  • 12,712
  • 7
  • 37
  • 53
  • his method is the one that i use. although i would change the defiition of ptr_to_container to be a container* – chacham15 Feb 14 '11 at 14:10
  • @chacham15 well, that makes sense if you use the second approach to container definitions but not if you use the first. – Christoffer Feb 14 '11 at 14:26
  • Ah, well, now that I thought a bit about this anyway I added an example of how the iterator could be used in the second approach as well. – Christoffer Feb 14 '11 at 14:33
0

Did you try casting to a vector *?

return ((vector *)(itr->ptr_to_container))->containter_end(itr->ptr_to_container);

However, are you sure you want to do this? You are using itr to call a function and then pass itr to that function. Including more context (more code) would help.

Mr. Shickadance
  • 5,283
  • 9
  • 45
  • 61
0

You need to explicitly cast *ptr_to_container to a vector pointer:

((__vector *)(itr->ptr_to_container))->container_end

Otherwise the compiler doesn't know what is the structure of the target.

Though, I don't really see why you want to have such a construction. It looks like you want to have object orientation here with inheritance, but without explicitly stating anything. It won't work well. In C, you'll have to use less general structures, or move to C++.

SurDin
  • 3,281
  • 4
  • 26
  • 28
0

If it must be void * use

int                                 
end(iterator *itr) {                
    return ((vector)(itr->ptr_to_container))->container_end(itr->ptr_to_container);
} 

or else specify in the iterator that it is a vector iterator

typedef struct __iterator {      
    vector *ptr_to_container;  
    int (*end)(struct __iterator *);
}iterator;  //probably you'll need to rename to make type of iterator clear

If you need to keep the abstraction (one iterator for all of you containers) nothing comes to mind atm...

RedX
  • 14,749
  • 1
  • 53
  • 76