The "object-orientedness" of C++ really boils down to implicitly passing the this pointer to member functions, inheritance + virtual functions, and namespaces. All of these can be emulated in what I would call "C with discipline". Just be consistent in your naming conventions, always use a common prefix for globally visible functions and types, and use structs of function pointers whenever you really need virtual functions.
And, before you mention it, use clang to avoid getting the page long templates related errors.
Type-generic data containers can still be implemented with void pointers and very little runtime overhead, for example: http://lxr.nginx.org/source/src/core/ngx_array.h
I am working in DSP project which was started with typical C++ OO BS, finally with ended up with C compiled as C++ + some simple templates for cases as above.
#define MAX(a,b) ({ \
typeof (a) _a = (a); \
typeof (b) _b = (b); \
_a > _b ? _a : _b; \
})
The inability to write template functions can be compensated by designing your function so that it takes a function pointer where the type-specific action occurs. auto max = [](auto a, auto b) {
return (a > b) ? a : b;
};
max (3.1415, 42); // returns double
max (42ul, 78u); // returns unsigned long
max (17, 16); // returns intHow is it template 'nonsense', when those templates do exactly that?
int maxi(int, int);
double: maxd(double, double);
...
#define max(x) _Generic((x), int: maxi, double: maxd, ...default: maxi)