Search code examples
c++referencec-preprocessor

Assignable-to function-like thing in c++


I'm writing code for a thing that uses Lisp-like data structures (i.e. cons cells) internally. So it makes sense for the two field members of the cons struct to be called x->car and x->cdr.

As you would probably expect, I assign to those fields. Sometimes it's chained, as in x->cdr->cdr->car (and yes, I do check to make sure the intermediary values are valid before doing this).

Because it's Lisp, however, I want to be able to use Lisp names for them, such as x->caddr, but that would obviously not work because it's chained pointers, not one single pointer.

Currently I am using a bunch of preprocessor macros like so:

#define car(x) ((x)->car)
#define cdr(x) ((x)->cdr)
#define caar(x) car(car(x))
#define cadr(x) car(cdr(x))
#define cdar(x) cdr(car(x))
#define cddr(x) cdr(cdr(x))
#define caaar(x) car(caar(x))
// and so on all the way up to caaaaaar / cddddddr

This allows me to write stuff like caddr(x) = y and have it work, because the macros expand into valid lvalues that can be assigned to.

However, the macros are not type checked. If I accidentally pass in a value that doesn't have car and cdr pointers, the error message is very hard to track down exactly what is the problem.

It also feels like a kludge too, as are most "preprocessor hacks".

I am looking for some way to express this that:

  1. Does type checking
  2. Is still a valid lvalue that can be assigned to
  3. Does not use the preprocessor

Any pointers?

(No pun intended)


Solution

  • answered by @273K's comment

    inline object*& car(object* x) { return x->car; }
    inline object*& cdr(object* x) { return x->cdr; }
    inline object*& caar(object* x) { return car(car(x)); }
    inline object*& cadr(object* x) { return car(cdr(x)); }
    inline object*& cdar(object* x) { return cdr(car(x)); }
    inline object*& cddr(object* x) { return cdr(cdr(x)); }
    inline object*& caaar(object* x) { return car(caar(x)); }
    // and so on
    

    somehow, I forgot about C++ references