Niklas R
Niklas R

Reputation: 16860

Templating in C using the Preprocessor

I'm wondering why I have never seen the following way to implement templates in C before. My idea was to make the Preprocessor to the templating-work.

container.h:

#ifndef TEMPLATE_TYPE
    #error "missing decalaration TEMPLATE_TYPE"
#endif

#define _CONCAT(a, b) a##b
#define _EVALUATOR(a, b) _CONCAT(a, b)
#define MAKE_NAME(a, b) _EVALUATOR(a, b)

typedef struct {
    TEMPLATE_TYPE   data;
} MAKE_NAME(Container_, TEMPLATE_TYPE);

main.c:

#define TEMPLATE_TYPE int
#include "container.h"

int main() {
    Container_int c;
    c.data = 99923;
}

So, what's the case?

  1. This is just considered "bad style"
  2. It's so obvious that nobody would write an article about it
  3. There are a lot of articles, just google man!

I would appreciate comments about this technique when you are not planning to answer with #3.

Upvotes: 2

Views: 3095

Answers (2)

glglgl
glglgl

Reputation: 91017

Instead of

typedef struct {
    TEMPLATE_TYPE   data;
} MAKE_NAME(Container_, TEMPLATE_TYPE)

you might want to do

#define MAKE_CONTAINER(type) typedef struct MAKE_NAME(Container_, type) { type data; } MAKE_NAME(Container_, type)

in order to be able to do

#include "container.h"
MAKE_CONTAINER(int);
MAKE_CONTAINER(double);

int main() {
    Container_int c; // one way to go
    struct Container_double d; // my preferred way: don't typedef when not needed; let the structs be obvious.

    c.data = 99923;
    d.data = 3.5;
}

Upvotes: 3

Graeme
Graeme

Reputation: 1495

You can do incredible things (good and evil) with the preprocessor. Whether it's considered bad style or not is a judgement call, and it largely depends on the quality, readability, and maintainability of the code that results. Complicated preprocessor macros are a pain to write, debug, and maintain. However, the best C code is the code you don't write, and macros are great for automatically generating variations on a theme.

Here are some good examples of preprocessor (ab)use:

The SimpleScalar code uses a pattern like your suggestion, above, where the #include is preceded by a #define that gives the header some direction.

If you're considering serious use of the preprocessor, you should look at the Boost preprocessor library. (Don't be put off by Boost's C++ roots, the preprocessor macros work fine with C.)

Upvotes: 5

Related Questions