add section about conditional compilation

This commit is contained in:
Johannes Loher 2018-06-07 23:08:10 +02:00
parent 2d43ed3eda
commit 1773b32d94

View file

@ -545,7 +545,7 @@ flag `--boundcheck=off`.
#### Static arrays
Static arrays are stored on he stack or in static memory, depending on where
they are defined. They have a fixed, compile-time known length. The length is
they are defined. They have a fixed, compile time known length. The length is
part of the type:
```D
@ -1357,8 +1357,8 @@ the `-cov` flag. When using DUB, just add the flag `--coverage`.
### String mixins
The mixin expression takes an arbitrary string and compiles it and generates instructions accordingly. This is a compile-time feature, so ths string needs
to be known at compile-time.
The mixin expression takes an arbitrary string and compiles it and generates instructions accordingly. This is a compile time feature, so ths string needs
to be known at compile time.
```D
mixin("int b = 5"); // compiles just fine
@ -1369,7 +1369,7 @@ mixin(compileTimeKnownString); // so does this
assert(c == 5);
immutable runTimeString = q{int c =5;};
mixin(runTimeString); // compile error, runTimeString is not known at compile-time
mixin(runTimeString); // compile error, runTimeString is not known at compile time
```
### Compile Time Function Evaluation (CTFE)
@ -1413,3 +1413,97 @@ void main() {
cn);
}
```
### Conditional compilation
D has several methods of conditional compilation which can be used for code
generation. Ds traits and the module `std.traits` contain many usefull tools
which can be used with the following constructs.
#### `static if` & `is`
`static if` conditionally compiles a code block based on a condition that can be
evaluated at compile time:
```D
foo(int x)() { // x is a template parameter and thus known at compile time
static if(x == 0)
writeln("x is 0");
else
writeln()
}
```
The `is` expression is used to check for valid types and to compare types:
```D
foo(T)() {
static if(is(T)) {
writeln("T is a valid type");
}
static if(is(T == int)) {
writeln("T is int");
}
static if(is(T : int)) {
writeln("T implicitly converts to int");
}
}
```
#### `static foreach`
`static foreach` allows you to iterate at compile time in order to generate
code. It is best explained by an example: The code
```D
import std.stdio;
void main() {
static foreach(element; ["foo", "bar", "baz"]) {
writeln(element);
}
}
```
effectively lowers to
```D
import std.stdio;
void main() {
writeln("foo");
writeln("bar");
writeln("baz");
}
```
which means there is no loop at runtime.
#### Template constraints
A template may be defined with any number of constraints that enforce some
properties of the template parameters:
```D
void foo(T)(T value)
if (is(T : long)) { // foo!T only valid if T implicitly converts to long
}
foo(42); // compiles, 42 is of type int which implicitly converts to long
foo("someString"); // compile error, strings do not implicitly convert to long
```
```D
void bar(T)(T value)
if (__traits(compiles, {T t = T.init; t.fly();})) { // bar!T only valid if we can initialize T and T has a method called fly which takes no parameters
}
struct MyStruct {
void fly() {}
}
MyStruct myStruct;
bar(myStruct); // compiles
bar(42); // compile error
```