__traits( compiles, a + b ); is( typeof( a + b ) );
template isNumArray(T) { enum isNumArray = __traits(compiles, { auto a = T.init[0]; // opIndex int static if( !__traits(isArithmetic,a) ) // , { static assert( __traits( compiles, a=a+a ) ); // static assert( __traits( compiles, a=aa ) ); // static assert( __traits( compiles, a=a*.0f ) ); // float } auto b = T.init.length; // length static assert( is( typeof(b) : size_t ) ); }); } auto mean(T)( T arr ) @property if( isNumArray!T ) in { assert( arr.length > 0 ); } body { // arr[index] arr.length // , arr[index] auto ret = arr[0] - arr[0]; // (0) foreach( i; 0 .. arr.length ) ret = ret + arr[i]; // += return ret * ( 1.0f / arr.length ); }
import std.string : format; struct Vec2 { float x=0, y=0; // auto opBinary(string op)( auto ref const Vec2 rhs ) const if( op == "+" || op == "-" ) { mixin( format( "return Vec2( x %1$s rhs.x, y %1$s rhs.y );", op ) ); } // auto opBinary(string op)( float rhs ) const if( op == "*" ) { return Vec2( x * rhs, y * rhs ); } } struct Triangle { Vec2 p1, p2, p3; // var[index] auto opIndex(size_t v) { switch(v) { case 0: return p1; case 1: return p2; case 2: return p3; default: throw new Exception( "triangle have only three elements" ); } } static pure size_t length() { return 3; } } void main() { auto f = [ 1.0f, 2, 3 ]; assert( f.mean == 2.0f ); // float auto v = [ Vec2(1,6), Vec2(2,7), Vec2(3,5) ]; assert( v.mean == Vec2(2,6) ); // user-defined auto t = Triangle( Vec2(1,6), Vec2(2,7), Vec2(3,5) ); assert( t.mean == Vec2(2,6) ); // user-defined }
is( T ); // T
Further, the type T in all cases is checked for semantic validity. is( T == Type ); // T Type is( T : Type ); // T Type
There are forms that create new alias. is( T ident );
In this case, with type T validity, an alias for it will be created under the name of ident. But it will be more interesting to combine such a form with any kind of verification. is( T ident : Type ); is( T ident == Type );
void foo(T)( T value ) { static if( is( TU : long ) ) // T long alias Num = U; // else alias Num = long; // long }
is( T == Specialization );
In this case, Specialization is one of the possible values: struct, union, class, interface, enum, function, delegate, const, immutable, shared. Accordingly, it is checked whether type T is a structure, a union, a class, etc. And there is a form that combines verification and declaration of alias. is( T ident == Specialization );
is( T == TypeTempl, TemplParams... ); is( T : TypeTempl, TemplParams... ); // alias' is( T ident == TypeTempl, TemplParams... ); is( T ident : TypeTempl, TemplParams... );
In this case, TypeTempl is the type description (composite), and TemplParams are the elements that make up TypeTempl. struct Foo(size_t N, T) if( N > 0 ) { T[N] data; } struct Bar(size_t N, T) if( N > 0 ) { float[N] arr; T value; } void func(U)( U val ) { static if( is( UE == S!(N,T), alias S, size_t N, T ) ) { pragma(msg, "struct like Foo: ", E ); pragma(msg, "S: ", S.stringof); pragma(msg, "N: ", N); pragma(msg, "T: ", T); } else static if( is( UT : T[X], X ) ) { pragma(msg, "associative array T[X]: ", U ); pragma(msg, "T(value): ", T); pragma(msg, "X(key): ", X); } else static if( is( UT : T[N], size_t N ) ) { pragma(msg, "static array T[N]: ", U ); pragma(msg, "T(value): ", T); pragma(msg, "N(length): ", N); } else pragma(msg, "other: ", U ); pragma(msg,""); } void main() { func( Foo!(10,double).init ); func( Bar!(12,string).init ); func( [ "hello": 23 ] ); func( [ 42: "habr" ] ); func( Foo!(8,short).init.data ); func( 0 ); }
struct like Foo: Foo!(10LU, double) S: Foo(ulong N, T) if (N > 0) N: 10LU T: double struct like Foo: Bar!(12LU, string) S: Bar(ulong N, T) if (N > 0) N: 12LU T: string associative array T[X]: int[string] T(value): int X(key): string associative array T[X]: string[int] T(value): string X(key): int static array T[N]: short[8] T(value): short N(length): 8LU other: int
class A { class B {} } pragma(msg, __traits(isNested,AB)); // true
void f1() { auto f2() { return 12; } pragma(msg,__traits(isNested,f2)); // true }
auto f1() { auto val = 12; struct S { auto f2() { return val; } } // f1 return S.init; } pragma(msg,__traits(isNested,typeof(f1()))); // true
struct Foo { float value; } pragma(msg, __traits(hasMember, Foo, "value")); // true pragma(msg, __traits(hasMember, Foo, "data")); // false
import std.stdio, std.string; string test(alias T)() { string ret; ret ~= is( typeof(T) == delegate ) ? "D " : is( typeof(T) == function ) ? "F " : "? "; ret ~= __traits(isVirtualMethod,T) ? "m|" : "-|"; ret ~= __traits(isVirtualFunction,T) ? "v|" : "-|"; ret ~= __traits(isAbstractFunction,T) ? "a|" : "-|"; ret ~= __traits(isFinalFunction,T) ? "f|" : "-|"; ret ~= __traits(isStaticFunction,T) ? "s|" : "-|"; ret ~= __traits(isOverrideFunction,T) ? "o|" : "-|"; return ret; } class A { static void stat() {} void simple1() {} void simple2() {} private void simple3() {} abstract void abstr() {} final void fnlNOver() {} } class B : A { override void simple1() {} final override void simple2() {} override void abstr() {} } class C : B { final override void abstr() {} } interface I { void abstr(); final void fnl() {} } struct S { void func(){} } void globalFunc() {} void main() { A a; B b; C c; I i; S s; writeln( " id T m|v|a|f|s|o|" ); writeln( "--------------------------" ); writeln( " lambda: ", test!(x=>x) ); writeln( " function: ", test!((){ return 3; }) ); writeln( " delegate: ", test!((){ return b; }) ); writeln( " s.func: ", test!(s.func) ); writeln( " global: ", test!(globalFunc) ); writeln( " a.stat: ", test!(a.stat) ); writeln( " a.simple1: ", test!(a.simple1) ); writeln( " a.simple2: ", test!(a.simple2) ); writeln( " a.simple3: ", test!(a.simple3) ); writeln( " a.abstr: ", test!(a.abstr) ); writeln( "a.fnlNOver: ", test!(a.fnlNOver) ); writeln( " b.simple1: ", test!(b.simple1) ); writeln( " b.simple2: ", test!(b.simple2) ); writeln( " b.abstr: ", test!(b.abstr) ); writeln( " c.abstr: ", test!(c.abstr) ); writeln( " i.abstr: ", test!(i.abstr) ); writeln( " i.fnl: ", test!(i.fnl) ); }
id T m|v|a|f|s|o| -------------------------- lambda: ? -|-|-|-|-|-| function: ? -|-|-|-|s|-| delegate: D -|-|-|-|-|-| s.func: F -|-|-|-|-|-| global: F -|-|-|-|s|-| a.stat: F -|-|-|-|s|-| a.simple1: F m|v|-|-|-|-| a.simple2: F m|v|-|-|-|-| a.simple3: F -|-|-|-|-|-| a.abstr: F m|v|a|-|-|-| a.fnlNOver: F -|v|-|f|-|-| b.simple1: F m|v|-|-|-|o| b.simple2: F m|v|-|f|-|o| b.abstr: F m|v|-|-|-|o| c.abstr: F m|v|-|f|-|o| i.abstr: F m|v|a|-|-|-| i.fnl: F -|-|a|f|-|-|
enum Foo; class Bar { @(42) @Foo void func() pure @nogc @property {} } pragma(msg, __traits(getAttributes, Bar.func)); // tuple(42, (Foo)), @nogc @property @Foo float value; pragma(msg, __traits(getAttributes, value)); // tuple((Foo)),
enum Foo; class Bar { @(42) @Foo void func() pure @nogc @property {} } pragma(msg, __traits(getFunctionAttributes, Bar.func)); // tuple("pure", "@nogc", "@property", "@system")
class Bar { float value; } Bar bar; __traits(getMember, bar, "value") = 10; // bar.value = 10;
import std.stdio; class A { void foo( float ) {} void foo( string ) {} int foo( int ) { return 12; } } void main() { foreach( f; __traits(getOverloads, A, "foo") ) writeln( typeof(f).stringof ); }
Result void(float _param_0) void(string _param_0) int(int _param_0)
class A { // , 1 , GC: // monitor, , 1, GC: float val1; // 1, GC: A val2; // 1, GC: void* val3; // 1, GC: void[] val4; // 2 { GC: , GC: } void function() val5; // 1, GC: void delegate() val6; // 2 { GC: , GC: } } enum bm = 0b101011000; // ||||||||+- // |||||||+-- monitor // ||||||+--- float val1 // |||||+---- A val2 // ||||+----- void* val3 // |||+------ void[] val4 // ||+------- void[] val4 // |+-------- void function() val5 // +--------- void delegate() val6 // 0---------- void delegate() val6 static assert( __traits(getPointerBitmap,A) == [10*size_t.sizeof, bm] ); struct B { float x, y, z; } static assert( __traits(getPointerBitmap,B) == [3*float.sizeof, 0] ); // B ,
import std.stdio; struct B { float value; void func() {} } alias F = B.func; void main() { writeln( __traits(parent,writeln).stringof ); // module stdio writeln( typeid( typeof( __traits(parent,F).value ) ) ); // float }
void func(T)( T val ) { ... }
import std.stdio; void func(T:long)( T val ) { writeln( "number" ); } void func(T: U[E], U, E)( T val ) if( is( E == string ) ) { writeln( "AA with string key" ); } void func(T: U[E], U, E)( T val ) if( is( E : long ) ) { writeln( "AA with num key" ); } void main() { func( 120 ); // number func( ["hello": 12] ); // AA with string key func( [10: 12] ); // AA with num key }
Source: https://habr.com/ru/post/261349/
All Articles