If you use make to build your software, one approach you can use to achieve a similar result is to let make generate your code based on the template you wrote, invoking something like sed or awk. I have used this approach many times, and although it lacks the flexibility and capabilities that C ++ templates offer, it is extremely transparent (unlike macros), it is very efficiently built and does not require any additional tools, except for the proven old school Unix utility (for example, make and sed ). The main disadvantage is that you will specify the search / replace lines in a different place (the line in the Makefile) than your code.
Note that often you are better off using function pointers and void pointers to just write one universal code base. However, if you want additional performance to eliminate unnecessary function calls, for example, in tight cycles, templates can be better and can be emulated as follows:
Write the template code using placeholder names with the name of the template, for example code.template.c
Write your non-template code using function calls for your template code, after replacing in the appropriate names, for example, my_int_func() or my_string_func()
Perhaps use #include to include the template code in code that is not associated with the template (for example, if your template will have inline functions)
Write your Makefile at:
- Create the βrealβ C files from the template.c file. You will have one Makefile entry for each template target, for example code.generated.c.
sed is a good replacement tool, but you can also use, for example, replace or awk or any of their equivalents on Windows - If necessary, compile the generated C files and link the generated objects
For instance:
code.template.c
void print_DATANAME_data(DATATYPE x) { printf("%SPECIFIER\n", x); }
code.c
#include <stdio.h> #include "printfuncs.generated.c" int main() { int i = 99; print_int_data(99); char *s = "hello"; print_str_data(s); float f = 1.234; print_float_data(f); }
Makefile
all: my_program my_program: code.c CC -o $@ code.c code.c: printfuncs.generated.c printfuncs.generated.c: code.template.c rm -f printfuncs.generated.c cat code.template.c | sed 's/DATANAME/int/g;s/DATATYPE/int/g;s/SPECIFIER/i/g;' >> printfuncs.generated.c cat code.template.c | sed 's/DATANAME/str/g;s/DATATYPE/char */g;s/SPECIFIER/s/g;' >> printfuncs.generated.c cat code.template.c | sed 's/DATANAME/float/g;s/DATATYPE/float/g;s/SPECIFIER/f/g;' >> printfuncs.generated.c
build
make
This will create a file printfuncs.generated.c (if this file does not exist or changed not so long ago as code.template.c), which will look like this:
void print_int_data(int x) { printf("%i", x); } void print_str_data(char * x) { printf("%s", x); } void print_float_data(float x) { printf("%f", x); }
Any compiler errors will point to this file, and you can either tinker with this file directly to compile it (after which you will need to update the template to prevent loss of changes), or edit the template. In any case, after your changes, what you need to do is run make to (try) compile again.
run
./my_program (or my_program.exe , if built on victory)