I have been reading about the template system in the D language and came upon a unusual construct, static if
.
From what I managed to grasp it is evaluated at compile time, but from what I have searched, the example shown here did not quite enlighten me.
template Factorial(ulong n)
{
static if(n < 2)
const Factorial = 1;
else
const Factorial = n * Factorial!(n - 1);
}
What does static if
do, and when should I use it?
the D static if
is the base for "conditional compilation", and plays an important role wherever a compile time decision about a variant of a code must be taken.
Since D doesn't have a preprocessor, things like
#ifdef xxx
compile_this_piece_of_code
#endif
can become
static if(xxx)
{
compile_this_pece_of_code
}
similarly, metaprogramming can happen also via static if:
template<int x>
struct traits
{ some definition calculated from x };
template<>
struct traits<0>
{ same definitions for the 0 particular case }
can be
template(int x)
{
static if(x==0)
{ some definitions }
else
{ some other same definitions }
even more definition common in the two cases
}
The wikipedia example is actually pretty simple:
template Factorial(ulong n)
{
static if(n < 2)
const Factorial = 1;
else
const Factorial = n * Factorial!(n - 1);
}
It is an eponymous template (See Jonathan's comment below). n
is the template parameter. So, what if you instead wrote:
template Factorial(ulong n)
{
if(n < 2) // NOTE: no static here
const Factorial = 1;
else
const Factorial = n * Factorial!(n - 1);
}
? - It will not work. Check http://dpaste.dzfl.pl/3fe074f2 . The reason is the fact that static if and "normal" if have different semantics. static if
takes an assignment expression ( http://dlang.org/version.html , section "Static If") that is evaluated at compile time, while normal if takes an expression that is evaluated at run-time.
Static if
is just one way to do the "conditional compilation" mentioned by Emilio. D also has the version
keyword. So Emilio's first conditional compilation example (which does not work in D) becomes something like:
version (XXX) {
// XXX defined
} else {
// XXX not defined
}
If you want to use static if for this, you would write something like:
enum int XXX = 10;
static if (XXX == 10) {
pragma(msg, "ten");
}
Andrei Alexandrescu has a good talk that you can watch here about static if in a C++ context (if that's what your asking for).
Link: http://channel9.msdn.com/Events/GoingNative/GoingNative-2012/Static-If-I-Had-a-Hammer
Short answer- it makes the syntax for some template metaprogramming a lot more intuitive.
Andrei Alexandrescu has lately been calling smart use of static if
"Design by Introspection", with some great examples (video, slides).
A direct example from his talk would be implementing a generic container such as a hash table using Robin Hood hashing, where an extra data (probe count) is kept with each entry in the table. With static if
we can optimize memory automatically by placing the probe count next to the key based on its alignment, optimize integer width for the index type, etc.
Paraphrased from the talk:
struct RobinHashTable(K, V, size_t maxLength) {
static if (maxLength < ushort.max-1) {
alias CellIdx = ushort;
} else {
alias CellIdx = uint;
}
static if (K.sizeof % 8 < 7) {
align(8) struct KV {
align(1):
K k;
ubyte cellData;
align(8):
V v;
}
} else {
align(8) struct KV {
align(8):
K k;
V v;
align(1):
ubyte cellData;
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With