11

For a typedef of a struct in C, I can't do this:

typedef struct {
    unsigned id;
    node_t *left;
    node_t *right;
} node_t;

because node_t is not known until it is defined, so it can't be used in its own definition. A bit of a Catch-22. However, I can use this workaround to make the desired self-referential type:

typedef struct node_s node_t;
struct node_s {
    unsigned id;
    node_t *left;
    node_t *right;
};

Similarly, I would like to do something like this for a C++ container referring to itself:

typedef pair<unsigned, pair<node_t *, node_t * > > node_t;

but of course, the compiler complains that it's never heard of node_t before it's defined node_t, as it would for the struct typedef above.

So is there a workaround like for the struct? Or some better way to do this? (And no, I don't want to use void pointers.)

Mark Adler
  • 101,978
  • 13
  • 118
  • 158
  • Does this help: [STL map onto itself?](http://stackoverflow.com/questions/1403501/stl-map-onto-itself) – Rahul Tripathi Dec 30 '15 at 07:40
  • 2
    You can look at realization of http://www.boost.org/doc/libs/1_57_0/boost/variant/recursive_variant.hpp or http://www.boost.org/doc/libs/1_57_0/boost/variant/recursive_wrapper.hpp – ForEveR Dec 30 '15 at 07:43
  • 1
    Your first case is a non-problem in C++: `struct node_t { node_t* left' node_t* right; };` is perfectly fine. Also, `std::pair` is not a container. – juanchopanza Dec 30 '15 at 08:08
  • Ah, sorry. I was going by the [Wikipedia STL page](https://en.wikipedia.org/wiki/Standard_Template_Library) which says that `pair` is a "simple container". And yes, I know that the first case is not a problem in C++, which is why I clarified with "in C". – Mark Adler Dec 30 '15 at 08:35

3 Answers3

10

You can do it like this:

struct node_t : std::pair<unsigned, std::pair<node_t *, node_t * > >
{};

After struct node_t the compiler knows that the type with name node_t exists, similar to a forward declaration.

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
4

The language does not support forward declaration of typedefs. Hence, you cannot use:

typedef pair<unsigned, pair<node_t *, node_t * > > node_t;

You can accomplish the notion of a container using struct node_t {...};, which I am sure needs no elaboration.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
1

You can self-reference a struct pointer if you name it (i.e. typedef struct <name> {...}). I usually use the following idiom:

typedef struct _node_t { // "Temporary" name "_node_t"
    unsigned id;
    struct _node_t *left; // Have to use "struct _node_t"
    struct _node_t *right;
} node_t; // "Final" name

That basically applies the previous answers to actual code.

Matthieu
  • 2,736
  • 4
  • 57
  • 87