Gamma was an experiment in templates without having to parse C. This led to some big annoyances that I guess aren't mentioned on that site but are in the PagedOut page[1]: when you instantiate a template "bar::[struct foo]" Gamma does a pretty bad job of knowing to copy the definition of "struct foo" (and all type definitions that "struct foo" depends on) from the caller into the template before compiling the instantiated template. (It gets even worse with circular dependencies, e.g., a "struct tree_node" that contains a "list::[struct tree_node]".)
More recently I've been playing with MaC[2], which solves those problems by only parsing the "header file" for each template. So it knows about all of the types in the program and can copy them between template instantiations as needed, but in the "main body" of the template you can use arbitrary GNU-C features. This has been a lot more reliable. As a test program for it I'm currently in the middle of writing an LR[k] parser generator[3] in MaC.
The big thing that gets annoying about all of these "don't-parse-the-code" approaches is there's no good way to do type inference. So you end up having to be pretty verbose, either writing out long template names everywhere or giving them shorter names that are less descriptive. And you can't do multiple dispatch, e.g., have "print(x);" forwarded to the 'right' print function based on the type of "x".
[1] https://pagedout.institute/download/PagedOut_007.pdf#page=44 [2] https://lair.masot.net/mac/ [3] https://lair.masot.net/git/mac.git/tree/examples/lrk