/* Sort 3 elements. */
void Q_SORT3(alias Q_LESS, alias Q_SWAP, Q_UINT) (Q_UINT q_a1, Q_UINT q_a2, Q_UINT q_a3)
{
if (Q_LESS(q_a2, q_a1)) {
if (Q_LESS(q_a3, q_a2))
Q_SWAP(q_a1, q_a3);
else {
Q_SWAP(q_a1, q_a2);
if (Q_LESS(q_a3, q_a2))
Q_SWAP(q_a2, q_a3);
}
}
else if (Q_LESS(q_a3, q_a2)) {
Q_SWAP(q_a2, q_a3);
if (Q_LESS(q_a2, q_a1))
Q_SWAP(q_a1, q_a2);
}
}
A D template function is distinguished by having two parameter lists, the compile time parameter list and the runtime parameter list. Q_UINT would be a type parameter with its type inferred from the function arguments. Q_LESS and Q_SWAP are alias parameters, which can be an alias to any symbol or type. This is often used to pass lambdas.
Note that D allows the following ways to pass a parameter:
1. by value
2. by reference
3. by name
4. by type
The alias parameters are "by name". C++ has by name parameters in the form of template template parameters, along with the restriction that such a parameter can only be a template. D allows any symbol or type to be passed by name.
Passing the lambdas by name means a direct function call/inlining rather than an indirect call through a function pointer.
Anyhow, with this example you can see how the rest can be fairly easily translated.
So, you might ask, what's the advantage?
1. name hygiene
2. your debugger will see the symbols
3. no ugly \ line splicing
4. no wacky do-while(0) kludge
5. the names are actual symbols rather than transitory apparitions seen only by the preprocessor
6. color syntax highlighting in your editor works
7. the compiler will check the syntax and give error messages in terms of the symbols, not generated preprocessor text
8. It's not going to conflict with another symbol named Q_SORT
Talk is cheap, show the code!