d编译时反射

原文
编译时反射使D元编程灵活而强大.
找出表达式的有效性:

__traits( compiles, a + b );
is( typeof( a + b ) );

__traits(compiles,expr)is(typeof(expr))都需要词法有效表达式.但后者不检查是否编译,而是检查是否存在表达式类型.
任务:创建接受与包含与数字"相似“的元素的数组”相似"对象,返回平均值(数学期望)函数

template isNumArray(T)
{
    enum isNumArray = __traits(compiles,
    {
        auto a = T.init[0]; 

        static if( !__traits(isArithmetic,a) ) // 
        {
            static assert( __traits( compiles, a=a+a ) ); //
            static assert( __traits( compiles, a=a-a ) ); //
            static assert( __traits( compiles, a=a*.0f ) ); //加减乘除
        }

        auto b = T.init.length; 
        static assert( is( typeof(b) : size_t ) );
    });
}

auto mean(T)( T arr ) @property if( isNumArray!T )
in { assert( arr.length > 0 ); } body
{//平均.
    auto ret = arr[0] - arr[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;

    auto opIndex(size_t v)
    {
        switch(v)
        {
            case 0: return p1;
            case 1: return p2;
            case 2: return p3;
            default: throw new Exception( "仅3元素,不要越界" );
        }
    }

    static pure size_t length() { return 3; }
}

void main()
{
    auto f = [ 1.0f, 2, 3 ];
    assert( f.mean == 2.0f ); // 

    auto v = [ Vec2(1,6), Vec2(2,7), Vec2(3,5) ];
    assert( v.mean == Vec2(2,6) ); // 

    auto t = Triangle( Vec2(1,6), Vec2(2,7), Vec2(3,5) );
    assert( t.mean == Vec2(2,6) ); // 
}
//细节不足,不要使用.

is(…)

is构造很强大.

is( T );

接下来,检查T类型:

is( T == Type );
is( T : Type );
//新别名
is( T ident : Type );
is( T ident == Type );

示例:

void foo(T)( T value )
{
    static if( is( T U : long ) ) // 
        alias Num = U; //
    else
        alias Num = long; // 
}

还可

is( T == 限定 );

这里,限定是:struct,union,class,interface,enum,function,delegate,const,immutable,shared等.因此,检查T是否是结构,联合,类等.
还可结合检查和别名:

is( T ident == 限定 )

另一个有趣技巧:模式匹配类型

is( T == TypeTempl, TemplParams... );
is( T : TypeTempl, TemplParams... );

is( T ident == TypeTempl, TemplParams... );
is( T ident : TypeTempl, TemplParams... );

此时,TypeTempl是描述(复合)类型,TemplParams是构成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( U E == S!(N,T), alias S, size_t N, T ) )
    {
        pragma(msg, "Foo一样的构: ", E );
        pragma(msg, "S: ", S.stringof);
        pragma(msg, "N: ", N);
        pragma(msg, "T: ", T);
    }
    else static if( is( U T : T[X], X ) )
    {
        pragma(msg, "关联数组T[X]: ", U );
        pragma(msg, "T(value): ", T);
        pragma(msg, "X(key):   ", X);
    }
    else static if( is( U T : T[N], size_t N ) )
    {
        pragma(msg, "静态数组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 );
}

输出:

Foo样构: Foo!(10LU, double)
S: Foo(ulong N, T) if (N > 0)
N: 10LU
T: double

Foo样构: Bar!(12LU, string)
S: Bar(ulong N, T) if (N > 0)
N: 12LU
T: string

关联数组T[X]: int[string]
T(value): int
X(key):   string

关联数组T[X]: string[int]
T(value): string
X(key):   int

静态数组T[N]: short[8]
T(value):  short
N(length): 8LU

other: int

__traits(keyWord, …)

意思
compiles表达式是否有效
isAbstractClass抽象类
isArithmetic算术类型(数字和枚举)
isAssociativeArray关联数组
isFinalClass终类(不能继承)
isPOD旧数据可通过简单逐字节复制来初化类型(隐藏字段,禁止使用析构函数)
isNested嵌套类型(依赖于上下文)
isFloating浮点数(包括复数)
isIntegral整数
isScalar标量类型(数字,枚举,指针),__vector(int[4])也是标量类型
isStaticArray静态数组
isUnsigned
isVirtualMethod虚方法
isVirtualFunction虚函数
isAbstractFunction抽象函数
isFinalFunction终函数
isStaticFunction静态函数
isOverrideFunction重载函数
isRef引用参数
isOut输出参数
isLazy惰参数(按需求值)
isSame表达式是否相同
hasMember类/构是否有字段/方法,第一个参数是类型(或类型对象),第二个参数是字段/方法名串.

示例:

class A { class B {} }
pragma(msg, __traits(isNested,A.B));
//是嵌套
void f1()
{
    auto f2() { return 12; }
    pragma(msg,__traits(isNested,f2)); // true
}

auto f1()
{
    auto val = 12;
    struct S { auto f2() { return val; } } 
    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

关于isFunction和isVirtualMethod和isVirtualFunction的区别

为了清楚起见,我写了个测试来显示差异

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|-|-|

isVirtualMethod可重载或已重载内容都返回true.如果未重载函数,而原本是final的,则不是虚方法,而是虚函数.
我无法解释λ函数(函数类型字面)附近的问号,它们未通过函数或委托测试.
后面的,提供示例,具体见文档:

enum Foo;
class Bar { @(42) @Foo void func() pure @nogc @property {} } 
pragma(msg, __traits(getAttributes, Bar.func)); // 
@?Foo float value;
pragma(msg, __traits(getAttributes, value)); // 
//
enum Foo;
class Bar { @(42) @Foo void func() pure @nogc @property {} } 
pragma(msg, __traits(getFunctionAttributes, Bar.func)); 
//
class Bar { float value; }
Bar bar; 
__traits(getMember, 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 );
}
//结果
void(float _param_0)
void(string _param_0)
int(int _param_0)
//
class A
{
    float val1; 
    A val2; 
    void* val3; 
    void[] val4; 
    void function() val5; 
    void delegate() val6; 
}

enum bm = 
0b101011000;
//||||||||+- 
//|||||||+-- 
//||||||+--- float val1
//|||||+---- A val2
//||||+----- void* val3
//|||+------ void[] val4 
//||+------- void[] val4 
//|+-------- void function() val5 
//+--------- void delegate() val6 
//0---------- void delegate() val6(第1个0)
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] ); 
//
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 ) { ... }

但是模板参数也有形式,比如is构造,用于检查隐式转换,甚至用于匹配模式.结合签名约束,可创建有趣的重载模板函数组合:

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" ); }
void func(T: U[E], U, E)( T val ) if( is( E : long ) ) { writeln( "带数字键AA" ); }

void main()
{
    func( 120 ); // 数字
    func( ["hello": 12] ); // 串AA 
    func( [10: 12] ); // 数字AA 
}
posted @   zjh6  阅读(14)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示