- Grammar
- Type Traits
- isArithmetic
- isFloating
- isIntegral
- isScalar
- isUnsigned
- isStaticArray
- isAssociativeArray
- isAbstractClass
- isFinalClass
- isCopyable
- isPOD
- toType
- isZeroInit
- hasCopyConstructor
- hasPostblit
- getAliasThis
- getPointerBitmap
- getVirtualFunctions
- getVirtualMethods
- classInstanceSize
- classInstanceAlignment
- initSymbol
- Function Traits
- Function Parameter Traits
- Symbol Traits
- fullyQualifiedName
- isNested
- isFuture
- isDeprecated
- isTemplate
- isModule
- isPackage
- hasMember
- identifier
- getAttributes
- getBitfieldOffset
- getBitfieldWidth
- getLinkage
- getLocation
- getMember
- getOverloads
- getCppNamespaces
- getVisibility
- fullyQualifiedName
- getProtection
- getTargetInfo
- getUnitTests
- parent
- child
- allMembers
- derivedMembers
- isSame
- compiles
Traits
Grammar
Traits are extensions to the language to enable programs, at compile time, to get at information internal to the compiler. This is also known as compile time reflection. It is done as a special, easily extended syntax (similar to Pragmas) so that new capabilities can be added as required.
TraitsExpression: __traits ( TraitsKeyword , TraitsArguments ) TraitsKeyword: isAbstractClass isArithmetic isAssociativeArray isFinalClass isPOD isNested isFuture isDeprecated isFloating isIntegral isScalar isStaticArray isUnsigned isDisabled isVirtualFunction isVirtualMethod isAbstractFunction isFinalFunction isStaticFunction isOverrideFunction isTemplate isRef isOut isLazy isReturnOnStack isCopyable isZeroInit isModule isPackage hasMember hasCopyConstructor hasPostblit identifier fullyQualifiedName getAliasThis getAttributes getBitfieldOffset getBitfieldWidth getFunctionAttributes getFunctionVariadicStyle getLinkage getLocation getMember getOverloads getParameterStorageClasses getPointerBitmap getCppNamespaces getVisibility getProtection getTargetInfo getVirtualFunctions getVirtualMethods getUnitTests parent child classInstanceSize classInstanceAlignment getVirtualIndex allMembers derivedMembers isSame compiles toType initSymbol parameters fullyQualifiedName TraitsArguments: TraitsArgument TraitsArgument , TraitsArguments TraitsArgument: AssignExpression Type
Type Traits
isArithmetic
If the arguments are all either types that are arithmetic types, or expressions that are typed as arithmetic types, then true is returned. Otherwise, false is returned. If there are no arguments, false is returned.
Arithmetic types are integral types and floating point types.
import std.stdio; void main() { int i; writeln(__traits(isArithmetic, int)); writeln(__traits(isArithmetic, i, i+1, int)); writeln(__traits(isArithmetic)); writeln(__traits(isArithmetic, int*)); }
true true false false
isFloating
If the arguments are all either types that are floating point types, or expressions that are typed as floating point types, then true is returned. Otherwise, false is returned. If there are no arguments, false is returned.
The floating point types are: float, double, real, ifloat, idouble, ireal, cfloat, cdouble, creal, vectors of floating point types, and enums with a floating point base type.
import core.simd : float4; enum E : float { a, b } static assert(__traits(isFloating, float)); static assert(__traits(isFloating, E)); static assert(__traits(isFloating, float4)); static assert(!__traits(isFloating, float[4]));
isIntegral
If the arguments are all either types that are integral types, or expressions that are typed as integral types, then true is returned. Otherwise, false is returned. If there are no arguments, false is returned.
The integral types are: byte, ubyte, short, ushort, int, uint, long, ulong, cent, ucent, bool, char, wchar, dchar, vectors of integral types, and enums with an integral base type.
import core.simd : int4; enum E { a, b } static assert(__traits(isIntegral, bool)); static assert(__traits(isIntegral, char)); static assert(__traits(isIntegral, int)); static assert(__traits(isIntegral, E)); static assert(__traits(isIntegral, int4)); static assert(!__traits(isIntegral, float)); static assert(!__traits(isIntegral, int[4])); static assert(!__traits(isIntegral, void*));
isScalar
If the arguments are all either types that are scalar types, or expressions that are typed as scalar types, then true is returned. Otherwise, false is returned. If there are no arguments, false is returned.
Scalar types are integral types, floating point types, pointer types, vectors of scalar types, and enums with a scalar base type.
import core.simd : int4, void16; enum E { a, b } static assert(__traits(isScalar, bool)); static assert(__traits(isScalar, char)); static assert(__traits(isScalar, int)); static assert(__traits(isScalar, float)); static assert(__traits(isScalar, E)); static assert(__traits(isScalar, int4)); static assert(__traits(isScalar, void*)); // Includes pointers! static assert(!__traits(isScalar, int[4])); static assert(!__traits(isScalar, void16)); static assert(!__traits(isScalar, void)); static assert(!__traits(isScalar, typeof(null))); static assert(!__traits(isScalar, Object));
isUnsigned
If the arguments are all either types that are unsigned types, or expressions that are typed as unsigned types, then true is returned. Otherwise, false is returned. If there are no arguments, false is returned.
The unsigned types are: ubyte, ushort, uint, ulong, ucent, bool, char, wchar, dchar, vectors of unsigned types, and enums with an unsigned base type.
import core.simd : uint4; enum SignedEnum { a, b } enum UnsignedEnum : uint { a, b } static assert(__traits(isUnsigned, bool)); static assert(__traits(isUnsigned, char)); static assert(__traits(isUnsigned, uint)); static assert(__traits(isUnsigned, UnsignedEnum)); static assert(__traits(isUnsigned, uint4)); static assert(!__traits(isUnsigned, int)); static assert(!__traits(isUnsigned, float)); static assert(!__traits(isUnsigned, SignedEnum)); static assert(!__traits(isUnsigned, uint[4])); static assert(!__traits(isUnsigned, void*));
isStaticArray
Works like isArithmetic, except it's for static array types.
import core.simd : int4; enum E : int[4] { a = [1, 2, 3, 4] } static array = [1, 2, 3]; // Not a static array: the type is inferred as int[] not int[3]. static assert(__traits(isStaticArray, void[0])); static assert(__traits(isStaticArray, E)); static assert(!__traits(isStaticArray, int4)); static assert(!__traits(isStaticArray, array));
isAssociativeArray
Works like isArithmetic, except it's for associative array types.
isAbstractClass
If the arguments are all either types that are abstract classes, or expressions that are typed as abstract classes, then true is returned. Otherwise, false is returned. If there are no arguments, false is returned.
import std.stdio; abstract class C { int foo(); } void main() { C c; writeln(__traits(isAbstractClass, C)); writeln(__traits(isAbstractClass, c, C)); writeln(__traits(isAbstractClass)); writeln(__traits(isAbstractClass, int*)); }
true true false false
isFinalClass
Works like isAbstractClass, except it's for final classes.
isCopyable
Takes one argument. If that argument is a copyable type then true is returned, otherwise false.
struct S { } static assert( __traits(isCopyable, S)); struct T { @disable this(this); // disable copy construction } static assert(!__traits(isCopyable, T));
isPOD
Takes one argument, which must be a type. It returns true if the type is a POD type, otherwise false.
toType
Takes a single argument, which must evaluate to an expression of type string. The contents of the string must correspond to the mangled contents of a type that has been seen by the implementation.
Only D mangling is supported. Other manglings, such as C++ mangling, are not.
The value returned is a type.
template Type(T) { alias Type = T; } Type!(__traits(toType, "i")) j = 3; // j is declared as type `int` static assert(is(Type!(__traits(toType, (int*).mangleof)) == int*)); __traits(toType, "i") x = 4; // x is also declared as type `int`
isZeroInit
Takes one argument which must be a type. If the type's default initializer is all zero bits then true is returned, otherwise false.
struct S1 { int x; } struct S2 { int x = -1; } static assert(__traits(isZeroInit, S1)); static assert(!__traits(isZeroInit, S2)); void test() { int x = 3; static assert(__traits(isZeroInit, typeof(x))); } // `isZeroInit` will always return true for a class C // because `C.init` is null reference. class C { int x = -1; } static assert(__traits(isZeroInit, C)); // For initializing arrays of element type `void`. static assert(__traits(isZeroInit, void));
hasCopyConstructor
The argument is a type. If it is a struct with a copy constructor, returns true. Otherwise, return false. Note that a copy constructor is distinct from a postblit.
import std.stdio; struct S { } class C { } struct P { this(ref P rhs) {} } struct B { this(this) {} } void main() { writeln(__traits(hasCopyConstructor, S)); // false writeln(__traits(hasCopyConstructor, C)); // false writeln(__traits(hasCopyConstructor, P)); // true writeln(__traits(hasCopyConstructor, B)); // false, this is a postblit }
hasPostblit
The argument is a type. If it is a struct with a postblit, returns true. Otherwise, return false. Note a postblit is distinct from a copy constructor.
import std.stdio; struct S { } class C { } struct P { this(ref P rhs) {} } struct B { this(this) {} } void main() { writeln(__traits(hasPostblit, S)); // false writeln(__traits(hasPostblit, C)); // false writeln(__traits(hasPostblit, P)); // false, this is a copy ctor writeln(__traits(hasPostblit, B)); // true }
getAliasThis
Takes one argument, a type. If the type has alias this declarations, returns a ValueSeq of the names (as strings) of the members used in those declarations. Otherwise returns an empty sequence.
alias AliasSeq(T...) = T; struct S1 { string var; alias var this; } static assert(__traits(getAliasThis, S1) == AliasSeq!("var")); static assert(__traits(getAliasThis, int).length == 0); pragma(msg, __traits(getAliasThis, S1)); pragma(msg, __traits(getAliasThis, int));
tuple("var") tuple()
getPointerBitmap
The argument is a type. The result is an array of size_t describing the memory used by an instance of the given type.
The first element of the array is the size of the type (for classes it is the classInstanceSize).
The following elements describe the locations of GC managed pointers within the memory occupied by an instance of the type. For type T, there are T.sizeof / size_t.sizeof possible pointers represented by the bits of the array values.
This array can be used by a precise GC to avoid false pointers.
void main() { static class C { // implicit virtual function table pointer not marked // implicit monitor field not marked, usually managed manually C next; size_t sz; void* p; void function () fn; // not a GC managed pointer } static struct S { size_t val1; void* p; C c; byte[] arr; // { length, ptr } void delegate () dg; // { context, func } } static assert (__traits(getPointerBitmap, C) == [6*size_t.sizeof, 0b010100]); static assert (__traits(getPointerBitmap, S) == [7*size_t.sizeof, 0b0110110]); }
getVirtualFunctions
The same as getVirtualMethods, except that final functions that do not override anything are included.
getVirtualMethods
The first argument is a class type or an expression of class type. The second argument is a string that matches the name of one of the functions of that class. The result is a symbol sequence of the virtual overloads of that function. It does not include final functions that do not override anything.
import std.stdio; class D { this() { } ~this() { } void foo() { } int foo(int) { return 2; } } void main() { D d = new D(); foreach (t; __traits(getVirtualMethods, D, "foo")) writeln(typeid(typeof(t))); alias b = typeof(__traits(getVirtualMethods, D, "foo")); foreach (t; b) writeln(typeid(t)); auto i = __traits(getVirtualMethods, d, "foo")[1](1); writeln(i); }
void() int() void() int() 2
classInstanceSize
Takes a single argument, which must evaluate to either a class type or an expression of class type. The result is of type size_t, and the value is the number of bytes in the runtime instance of the class type. It is based on the static type of a class, not the polymorphic type.
classInstanceAlignment
Takes a single argument, which must evaluate to either a class type or an expression of class type. The result is of type size_t, and the value is the alignment of a runtime instance of the class type. It is based on the static type of a class, not the polymorphic type.
initSymbol
Takes a single argument, which must evaluate to a class, struct or union type. Returns a const(void)[] that holds the initial state of any instance of the supplied type. The slice is constructed for any type T as follows:
- ptr points to either the initializer symbol of T or null if T is a zero-initialized struct/union.
- length is equal to the size of an instance, i.e. T.sizeof for a struct/union and __traits(classInstanceSize, T) for a class.
This trait matches the behaviour of TypeInfo.initializer() but can also be used when TypeInfo is not available.
This trait is not available during CTFE because the actual address of the initializer symbol will be set by the linker and hence is not available at compile time.
import core.stdc.stdlib; class C { int i = 4; } /// Initializes a malloc'ed instance of `C` void main() { const void[] initSym = __traits(initSymbol, C); void* ptr = malloc(initSym.length); scope (exit) free(ptr); // Note: allocated memory will only be written to through `c`, so cast is safe ptr[0..initSym.length] = cast(void[]) initSym[]; C c = cast(C) ptr; assert(c.i == 4); }
Function Traits
isDisabled
Takes one argument and returns true if it's a function declaration marked with @disable.
struct Foo { @disable void foo(); void bar(){} } static assert(__traits(isDisabled, Foo.foo)); static assert(!__traits(isDisabled, Foo.bar));
For any other declaration, even if @disable is a syntactically valid attribute, false is returned because the annotation has no effect.
@disable struct Bar{} static assert(!__traits(isDisabled, Bar));
getVirtualIndex
Takes a single argument which must evaluate to a function. The result is a ptrdiff_t containing the index of that function within the vtable of the parent type. If the function passed in is final and does not override a virtual function, -1 is returned instead.
isVirtualFunction
The same as isVirtualMethod, except that final functions that don't override anything return true.
isVirtualMethod
Takes one argument. If that argument is a virtual function, true is returned, otherwise false. Final functions that don't override anything return false.
import std.stdio; struct S { void bar() { } } class C { void bar() { } } void main() { writeln(__traits(isVirtualMethod, C.bar)); // true writeln(__traits(isVirtualMethod, S.bar)); // false }
isAbstractFunction
Takes one argument. If that argument is an abstract function, true is returned, otherwise false.
import std.stdio; struct S { void bar() { } } class C { void bar() { } } class AC { abstract void foo(); } void main() { writeln(__traits(isAbstractFunction, C.bar)); // false writeln(__traits(isAbstractFunction, S.bar)); // false writeln(__traits(isAbstractFunction, AC.foo)); // true }
isFinalFunction
Takes one argument. If that argument is a final function, true is returned, otherwise false.
import std.stdio; struct S { void bar() { } } class C { void bar() { } final void foo(); } final class FC { void foo(); } void main() { writeln(__traits(isFinalFunction, C.bar)); // false writeln(__traits(isFinalFunction, S.bar)); // false writeln(__traits(isFinalFunction, C.foo)); // true writeln(__traits(isFinalFunction, FC.foo)); // true }
isOverrideFunction
Takes one argument. If that argument is a function marked with override, true is returned, otherwise false.
import std.stdio; class Base { void foo() { } } class Foo : Base { override void foo() { } void bar() { } } void main() { writeln(__traits(isOverrideFunction, Base.foo)); // false writeln(__traits(isOverrideFunction, Foo.foo)); // true writeln(__traits(isOverrideFunction, Foo.bar)); // false }
isStaticFunction
Takes one argument. If that argument is a static function, meaning it has no context pointer, true is returned, otherwise false.
struct A { int foo() { return 3; } static int boo(int a) { return a; } } void main() { assert(__traits(isStaticFunction, A.boo)); assert(!__traits(isStaticFunction, A.foo)); assert(__traits(isStaticFunction, main)); }
isReturnOnStack
Takes one argument which must either be a function symbol, function literal, a delegate, or a function pointer. It returns a bool which is true if the return value of the function is returned on the stack via a pointer to it passed as a hidden extra parameter to the function.
struct S { int[20] a; } int test1(); S test2(); static assert(__traits(isReturnOnStack, test1) == false); static assert(__traits(isReturnOnStack, test2) == true);
- Returning values in registers is often faster, so this can be used as a check on a hot function to ensure it is using the fastest method.
- When using inline assembly to correctly call a function.
- Testing that the compiler does this correctly is normally hackish and awkward, this enables efficient, direct, and simple testing.
getFunctionVariadicStyle
Takes one argument which must either be a function symbol, or a type that is a function, delegate or a function pointer. It returns a string identifying the kind of variadic arguments that are supported.
result | kind | access | example |
---|---|---|---|
"none" | not a variadic function | void foo(); | |
"argptr" | D style variadic function | _argptr and _arguments | void bar(...) |
"stdarg" | C style variadic function | core.stdc.stdarg | extern (C) void abc(int, ...) |
"typesafe" | typesafe variadic function | array on stack | void def(int[] ...) |
import core.stdc.stdarg; void novar() {} extern(C) void cstyle(int, ...) {} extern(C++) void cppstyle(int, ...) {} void dstyle(...) {} void typesafe(int[]...) {} static assert(__traits(getFunctionVariadicStyle, novar) == "none"); static assert(__traits(getFunctionVariadicStyle, cstyle) == "stdarg"); static assert(__traits(getFunctionVariadicStyle, cppstyle) == "stdarg"); static assert(__traits(getFunctionVariadicStyle, dstyle) == "argptr"); static assert(__traits(getFunctionVariadicStyle, typesafe) == "typesafe"); static assert(__traits(getFunctionVariadicStyle, (int[] a...) {}) == "typesafe"); static assert(__traits(getFunctionVariadicStyle, typeof(cstyle)) == "stdarg");
getFunctionAttributes
Takes one argument which must either be a function symbol, function literal, or a function pointer. It returns a string ValueSeq of all the attributes of that function excluding any user-defined attributes (UDAs can be retrieved with the getAttributes trait). If no attributes exist it will return an empty sequence.
Note: The order of the attributes in the returned sequence is implementation-defined and should not be relied upon.A list of currently supported attributes are:
- pure, nothrow, @nogc, @property, @system, @trusted, @safe, ref and @live
Additionally the following attributes are only valid for non-static member functions:
- const, immutable, inout, shared
int sum(int x, int y) pure nothrow { return x + y; } pragma(msg, __traits(getFunctionAttributes, sum)); struct S { void test() const @system { } } pragma(msg, __traits(getFunctionAttributes, S.test));
tuple("pure", "nothrow", "@system") tuple("const", "@system")
Note that some attributes can be inferred. For example:
pragma(msg, __traits(getFunctionAttributes, (int x) @trusted { return x * 2; }));
tuple("pure", "nothrow", "@nogc", "@trusted")
Function Parameter Traits
isRef, isOut, isLazy
Takes one argument. If that argument is a declaration, true is returned if it is ref, out, or lazy, otherwise false.
void fooref(ref int x) { static assert(__traits(isRef, x)); static assert(!__traits(isOut, x)); static assert(!__traits(isLazy, x)); } void fooout(out int x) { static assert(!__traits(isRef, x)); static assert(__traits(isOut, x)); static assert(!__traits(isLazy, x)); } void foolazy(lazy int x) { static assert(!__traits(isRef, x)); static assert(!__traits(isOut, x)); static assert(__traits(isLazy, x)); }
getParameterStorageClasses
Takes two arguments. The first must either be a function symbol, a function call, or a type that is a function, delegate or a function pointer. The second is an integer identifying which parameter, where the first parameter is 0. It returns a ValueSeq of strings representing the storage classes of that parameter.
ref int foo(return ref const int* p, scope int* a, out int b, lazy int c); static assert(__traits(getParameterStorageClasses, foo, 0)[0] == "return"); static assert(__traits(getParameterStorageClasses, foo, 0)[1] == "ref"); static assert(__traits(getParameterStorageClasses, foo, 1)[0] == "scope"); static assert(__traits(getParameterStorageClasses, foo, 2)[0] == "out"); static assert(__traits(getParameterStorageClasses, typeof(&foo), 3)[0] == "lazy"); int* p, a; int b, c; static assert(__traits(getParameterStorageClasses, foo(p, a, b, c), 1)[0] == "scope"); static assert(__traits(getParameterStorageClasses, foo(p, a, b, c), 2)[0] == "out"); static assert(__traits(getParameterStorageClasses, foo(p, a, b, c), 3)[0] == "lazy");
parameters
May only be used inside a function. Takes no arguments, and returns an lvalue sequence of the enclosing function's parameters.
alias AliasSeq(A...) = A; void f(int n, char c) { alias PS = __traits(parameters); PS[0]++; // increment n static assert(is(typeof(PS) == AliasSeq!(int, char))); // output parameter names static foreach (i, p; PS) { pragma(msg, __traits(identifier, p)); } } int add(int x, int y) { return x + y; } int forwardToAdd(int x, int y) { return add(__traits(parameters)); // equivalent to; //return add(x, y); }
If the function is nested, the parameters returned are those of the inner function, not the outer one.
int nestedExample(int x) { // outer function's parameters static assert(typeof(__traits(parameters)).length == 1); int add(int x, int y) { // inner function's parameters static assert(typeof(__traits(parameters)).length == 2); return x + y; } return add(x, x); }
class C { int opApply(int delegate(size_t, C) dg) { if (dg(0, this)) return 1; return 0; } } void foreachExample(C c, int x) { foreach(idx; 0..5) { static assert(is(typeof(__traits(parameters)) == AliasSeq!(C, int))); } foreach(idx, elem; c) { // __traits(parameters) sees past the delegate passed to opApply static assert(is(typeof(__traits(parameters)) == AliasSeq!(C, int))); } }
Symbol Traits
fullyQualifiedName
Gets the fully qualified name of a type or symbol.
module myModule; int i; static assert(__traits(fullyQualifiedName, i) == "myModule.i"); struct MyStruct {} static assert(__traits(fullyQualifiedName, const MyStruct[]) == "const(myModule.MyStruct[])");
isNested
Takes one argument. It returns true if the argument is a nested type which internally stores a context pointer, otherwise it returns false. Nested types can be classes, structs, and functions.
isFuture
Takes one argument. It returns true if the argument is a symbol marked with the @__future attribute, otherwise false. Currently, only functions and variable declarations have support for the @__future keyword.
isDeprecated
Takes one argument. It returns true if the argument is a symbol marked with the deprecated keyword, otherwise false.
deprecated("No longer supported") int i; struct A { int foo() { return 1; } deprecated("please use foo") int bar() { return 1; } } static assert(__traits(isDeprecated, i)); static assert(!__traits(isDeprecated, A.foo)); static assert(__traits(isDeprecated, A.bar));
isTemplate
Takes one argument. If that argument or any of its overloads is a template then true is returned, otherwise false.
void foo(T)(){} static assert(__traits(isTemplate, foo)); static assert(!__traits(isTemplate, foo!int())); static assert(!__traits(isTemplate, "string"));
isModule
Takes one argument. If that argument is a symbol that refers to a module then true is returned, otherwise false. Package modules are considered to be modules even if they have not been directly imported as modules.
import core.thread; import std.algorithm.sorting; // A regular package (no package.d) static assert(!__traits(isModule, core)); // A package module (has a package.d file) // Note that we haven't imported std.algorithm directly. // (In other words, we don't have an "import std.algorithm;" directive.) static assert(__traits(isModule, std.algorithm)); // A regular module static assert(__traits(isModule, std.algorithm.sorting));
isPackage
Takes one argument. If that argument is a symbol that refers to a package then true is returned, otherwise false.
import std.algorithm.sorting; static assert(__traits(isPackage, std)); static assert(__traits(isPackage, std.algorithm)); static assert(!__traits(isPackage, std.algorithm.sorting));
hasMember
The first argument is a type that has members, or is an expression of a type that has members. The second argument is a string. If the string is a valid property of the type, true is returned, otherwise false.
import std.stdio; struct S { int m; } void main() { S s; static assert(__traits(hasMember, S, "m")); static assert(__traits(hasMember, s, "m")); static assert(!__traits(hasMember, S, "y")); static assert(!__traits(hasMember, S, "write")); // false, but callable like a member via UFCS static assert(__traits(hasMember, int, "sizeof")); static assert(__traits(hasMember, 5, "sizeof")); }
identifier
Takes one argument, a symbol. Returns the identifier for that symbol as a string literal.
int var = 123; static assert(__traits(identifier, var) == "var");
getAttributes
Takes one argument, a symbol. Returns a sequence of all attached user-defined attributes. If no UDAs exist it will return an empty sequence
For more information, see: User-Defined Attributes
@(3) int a; @("string", 7) int b; enum Foo; @Foo int c; pragma(msg, __traits(getAttributes, a)); pragma(msg, __traits(getAttributes, b)); pragma(msg, __traits(getAttributes, c));
tuple(3) tuple("string", 7) tuple((Foo))
getBitfieldOffset
Takes one argument, a qualified name that resolve to a field in a struct or class.
If the field is a bitfield, it returns as a uint the bit number of the least significant bit in the field. The rightmost bit is at offset 0, the leftmost bit is at offset 31 (for 32 bit int fields).
If the field is a not bitfield, it returns as a uint the number 0.
// OK with -preview=bitfields struct S { int a,b; int :2, c:3; } static assert(__traits(getBitfieldOffset, S.b) == 0); static assert(__traits(getBitfieldOffset, S.c) == 2);
getBitfieldWidth
Takes one argument, a qualified name that resolve to a field in a struct or class.
If the field is a bitfield, it returns as a uint the width of the bit field as a number of bits.
If the field is a not bitfield, it returns the number of bits in the type.
// OK with -preview=bitfields struct S { int a,b; int :2, c:3; } static assert(__traits(getBitfieldWidth, S.b) == 32); static assert(__traits(getBitfieldWidth, S.c) == 3);
getLinkage
Takes one argument, which is a declaration symbol, or the type of a function, delegate, pointer to function, struct, class, or interface. Returns a string representing the LinkageAttribute of the declaration. The string is one of:
- "D"
- "C"
- "C++"
- "Windows"
- "Objective-C"
- "System"
extern (C) int fooc(); alias aliasc = fooc; static assert(__traits(getLinkage, fooc) == "C"); static assert(__traits(getLinkage, aliasc) == "C"); extern (C++) struct FooCPPStruct {} extern (C++) class FooCPPClass {} extern (C++) interface FooCPPInterface {} static assert(__traits(getLinkage, FooCPPStruct) == "C++"); static assert(__traits(getLinkage, FooCPPClass) == "C++"); static assert(__traits(getLinkage, FooCPPInterface) == "C++");
getLocation
Takes one argument which is a symbol. To disambiguate between overloads, pass the result of getOverloads with the desired index, to getLocation. Returns a ValueSeq of a string and two ints which correspond to the filename, line number and column number where the argument was declared.
getMember
Takes two arguments, the second must be a string. The result is an expression formed from the first argument, followed by a ‘.’, followed by the second argument as an identifier.
import std.stdio; struct S { int mx; static int my; } void main() { S s; __traits(getMember, s, "mx") = 1; // same as s.mx=1; writeln(__traits(getMember, s, "m" ~ "x")); // 1 // __traits(getMember, S, "mx") = 1; // error, no this for S.mx __traits(getMember, S, "my") = 2; // ok }
getOverloads
- The first argument is an aggregate type or instance, or a module.
- The second argument is a string that matches the name of the member(s) to return.
- The third argument is a bool, and is optional. If true, the result will also include template overloads.
- The result is a symbol sequence of all the overloads of the supplied name.
import std.stdio; class D { void foo() { } int foo(int) { return 2; } void bar(T)() { return T.init; } class bar(int n) {} } void main() { D d = new D(); alias fooOverloads = __traits(getOverloads, D, "foo"); foreach (o; fooOverloads) writeln(typeid(typeof(o))); // typeof on a symbol sequence gives a type sequence foreach (T; typeof(fooOverloads)) writeln(typeid(T)); // calls d.foo(3) auto i = __traits(getOverloads, d, "foo")[1](3); assert(i == 2); // pass true to include templates // calls std.stdio.writeln(i) __traits(getOverloads, std.stdio, "writeln", true)[0](i); foreach (o; __traits(getOverloads, D, "bar", true)) writeln(o.stringof); }
void function() int function(int) void function() int function(int) 2 bar(T)() bar(int n)
getCppNamespaces
The argument is a symbol. The result is a ValueSeq of strings, possibly empty, that correspond to the namespaces the symbol resides in.
extern(C++, "ns") struct Foo {} struct Bar {} extern(C++, __traits(getCppNamespaces, Foo)) struct Baz {} static assert(__traits(getCppNamespaces, Foo) == __traits(getCppNamespaces, Baz)); void main() { static assert(__traits(getCppNamespaces, Foo)[0] == "ns"); static assert(!__traits(getCppNamespaces, Bar).length); static assert(__traits(getCppNamespaces, Foo) == __traits(getCppNamespaces, Baz)); }
getVisibility
The argument is a symbol. The result is a string giving its visibility level: "public", "private", "protected", "export", or "package".
import std.stdio; class D { export void foo() { } public int bar; } void main() { D d = new D(); auto i = __traits(getVisibility, d.foo); writeln(i); auto j = __traits(getVisibility, d.bar); writeln(j); }
export public
fullyQualifiedName
Takes one argument, which can be a type, expression, or symbol, and returns a string.
- A type returns a string representing the type.
- A expression returns a string representing the type of the expression.
- A symbol returns a string representing the fully qualified name of the symbol.
module plugh; import std.stdio; void main() { auto s = __traits(fullyQualifiedName, int); writeln(s); auto t = __traits(fullyQualifiedName, 1.0); writeln(t); auto u = __traits(fullyQualifiedName, t); writeln(u); }
int double plugh.main.t
getProtection
A backward-compatible alias for getVisibility.
getTargetInfo
Receives a string key as argument. The result is an expression describing the requested target information.
version (CppRuntime_Microsoft) static assert(__traits(getTargetInfo, "cppRuntimeLibrary") == "libcmt");
Keys are implementation defined, allowing relevant data for exotic targets. A reliable subset exists which are always available:
- "cppRuntimeLibrary" - The C++ runtime library affinity for this toolchain
- "cppStd" - The version of the C++ standard supported by extern(C++) code, equivalent to the __cplusplus macro in a C++ compiler
- "floatAbi" - Floating point ABI; may be "hard", "soft", or "softfp"
- "objectFormat" - Target object format
getUnitTests
Takes one argument, a symbol of an aggregate (e.g. struct/class/module). The result is a symbol sequence of all the unit test functions of that aggregate. The functions returned are like normal nested static functions, CTFE will work and UDAs will be accessible.
module foo; import core.runtime; import std.stdio; struct name { string name; } class Foo { unittest { writeln("foo.Foo.unittest"); } } @name("foo") unittest { writeln("foo.unittest"); } template Tuple (T...) { alias Tuple = T; } shared static this() { // Override the default unit test runner to do nothing. After that, "main" will // be called. Runtime.moduleUnitTester = { return true; }; } void main() { writeln("start main"); alias tests = Tuple!(__traits(getUnitTests, foo)); static assert(tests.length == 1); alias attributes = Tuple!(__traits(getAttributes, tests[0])); static assert(attributes.length == 1); foreach (test; tests) test(); foreach (test; __traits(getUnitTests, Foo)) test(); }
By default, the above will print:
start main foo.unittest foo.Foo.unittest
parent
Takes a single argument which must evaluate to a symbol. The result is the symbol that is the parent of it.
child
Takes two arguments. The first must be a symbol or expression. The second is a symbol, such as an alias to a member of the first argument. The result is the second argument interpreted with its this context set to the value of the first argument.
import std.stdio; struct A { int i; int foo(int j) { return i * j; } T bar(T)(T t) { return i + t; } } alias Ai = A.i; alias Abar = A.bar!int; void main() { A a; __traits(child, a, Ai) = 3; writeln(a.i); writeln(__traits(child, a, A.foo)(2)); writeln(__traits(child, a, Abar)(5)); }
3 6 8
allMembers
Takes a single argument, which must evaluate to either a module, a struct, a union, a class, an interface, an enum, or a template instantiation.
A sequence of string literals is returned, each of which is the name of a member of that argument combined with all of the members of its base classes (if the argument is a class). No name is repeated. Builtin properties are not included.
import std.stdio; class D { this() { } ~this() { } void foo() { } int foo(int) { return 0; } } void main() { auto b = [ __traits(allMembers, D) ]; writeln(b); // ["__ctor", "__dtor", "foo", "toString", "toHash", "opCmp", "opEquals", // "Monitor", "factory"] }
The order in which the strings appear in the result is not defined.
derivedMembers
Takes a single argument, which must evaluate to either a type or an expression of type. A sequence of string literals is returned, each of which is the name of a member of that type. No name is repeated. Base class member names are not included. Builtin properties are not included.
import std.stdio; class D { this() { } ~this() { } void foo() { } int foo(int) { return 0; } } void main() { auto a = [__traits(derivedMembers, D)]; writeln(a); // ["__ctor", "__dtor", "foo"] }
The order in which the strings appear in the result is not defined.
isSame
Compares two arguments and evaluates to bool.
The result is true if the two arguments are the same symbol (once aliases are resolved).
struct S { } int foo(); int bar(); static assert(__traits(isSame, foo, foo)); static assert(!__traits(isSame, foo, bar)); static assert(!__traits(isSame, foo, S)); static assert(__traits(isSame, S, S)); static assert(!__traits(isSame, object, S)); static assert(__traits(isSame, object, object)); alias daz = foo; static assert(__traits(isSame, foo, daz));
The result is true if the two arguments are expressions made up of literals or enums that evaluate to the same value.
enum e = 3; static assert(__traits(isSame, (e), 3)); static assert(__traits(isSame, 5, 2 + e));
If the two arguments are both lambda functions (or aliases to lambda functions), then they are compared for equality. For the comparison to be computed correctly, the following conditions must be met for both lambda functions:
- The lambda function arguments must not have a template instantiation as an explicit argument type. Any other argument types (basic, user-defined, template) are supported.
- The lambda function body must contain a single expression (no return statement) which contains only numeric values, manifest constants, enum values, function arguments and function calls. If the expression contains local variables or return statements, the function is considered incomparable.
If these constraints aren't fulfilled, the function is considered incomparable and the result is false.
static assert(__traits(isSame, (a, b) => a + b, (c, d) => c + d)); static assert(__traits(isSame, a => ++a, b => ++b)); static assert(!__traits(isSame, (int a, int b) => a + b, (a, b) => a + b)); static assert(__traits(isSame, (a, b) => a + b + 10, (c, d) => c + d + 10));
int f() { return 2; } void test(alias pred)() { // f() from main is a different function from top-level f() static assert(!__traits(isSame, (int a) => a + f(), pred)); } void main() { // lambdas accessing local variables are considered incomparable int b; static assert(!__traits(isSame, a => a + b, a => a + b)); // lambdas calling other functions are comparable int f() { return 3;} static assert(__traits(isSame, a => a + f(), a => a + f())); test!((int a) => a + f())(); }
class A { int a; this(int a) { this.a = a; } } class B { int a; this(int a) { this.a = a; } } static assert(__traits(isSame, (A a) => ++a.a, (A b) => ++b.a)); // lambdas with different data types are considered incomparable, // even if the memory layout is the same static assert(!__traits(isSame, (A a) => ++a.a, (B a) => ++a.a));
If the two arguments are tuples then the result is true if the two tuples, after expansion, have the same length and if each pair of nth argument respects the constraints previously specified.
import std.meta; struct S { } // like __traits(isSame,0,0) && __traits(isSame,1,1) static assert(__traits(isSame, AliasSeq!(0,1), AliasSeq!(0,1))); // like __traits(isSame,S,std.meta) && __traits(isSame,1,1) static assert(!__traits(isSame, AliasSeq!(S,1), AliasSeq!(std.meta,1))); // the length of the sequences is different static assert(!__traits(isSame, AliasSeq!(1), AliasSeq!(1,2)));
compiles
Returns a bool true if all of the arguments compile (are semantically correct). The arguments can be symbols, types, or expressions that are syntactically correct. The arguments cannot be statements or declarations - instead these can be wrapped in a function literal expression.
If there are no arguments, the result is false.
static assert(!__traits(compiles)); static assert(__traits(compiles, 1 + 1)); // expression static assert(__traits(compiles, typeof(1))); // type static assert(__traits(compiles, object)); // symbol static assert(__traits(compiles, 1, 2, 3, int, long)); static assert(!__traits(compiles, 3[1])); // semantic error static assert(!__traits(compiles, 1, 2, 3, int, long, 3[1])); enum n = 3; // wrap a declaration/statement in a function literal static assert(__traits(compiles, { int[n] arr; })); static assert(!__traits(compiles, { foreach (e; n) {} })); struct S { static int s1; int s2; } static assert(__traits(compiles, S.s1 = 0)); static assert(!__traits(compiles, S.s2 = 0)); static assert(!__traits(compiles, S.s3)); int foo(); static assert(__traits(compiles, foo)); static assert(__traits(compiles, foo + 1)); // call foo with optional parens static assert(!__traits(compiles, &foo + 1));
This is useful for:
- Giving better error messages (using static assert) inside generic code than the sometimes hard to follow compiler ones.
- Doing a finer grained specialization than template partial specialization allows for.