D语言中国主页  D语言编辑器SciTE4D   DWin库 D语言官方网站
D语言编译器1.x最新版 OpenSource   Tango   webnews  Wiki

查看完整版本: 19 D语言 模板 Templates

yidabu 2007-4-26 15:59

19 D语言 模板 Templates

19 D语言 模板 Templates知识若不分享 实在没有意义 http://www.d-programming-language-china.org 20070424点击下面网址查看原文:http://www.d-programming-language-china.org        by:        uFramer        D语言论坛 http://www.d-programming-language-china.org        from:        http://www.digitalmars.com/d/template.html        version:        基于D 1.013        (Apr 19, 2007)        QUOTE:                                I think that I can safely say that nobody understands template mechanics. -- Richard Deyman                Templates are D's approach to generic programming. Templates are defined with a TemplateDeclaration:        QUOTE:                                TemplateDeclaration:                    template TemplateIdentifier ( TemplateParameterList )                        { DeclDefs }                                TemplateIdentifier:                    Identifier                                TemplateParameterList                    TemplateParameter                    TemplateParameter , TemplateParameterList                                TemplateParameter:                    TemplateTypeParameter                    TemplateValueParameter                    TemplateAliasParameter                    TemplateTupleParameter                                TemplateTypeParameter:                    Identifier                    Identifier TemplateTypeParameterSpecialization                    Identifier TemplateTypeParameterDefault                    Identifier TemplateTypeParameterSpecialization TemplateTypeParameterDefault                                TemplateTypeParameterSpecialization:                     : Type                                TemplateTypeParameterDefault:                     = Type                                TemplateValueParameter:                    Declaration                    Declaration TemplateValueParameterSpecialization                    Declaration TemplateValueParameterDefault                    Declaration TemplateValueParameterSpecialization TemplateValueParameterDefault                                TemplateValueParameterSpecialization:                     : ConditionalExpression                                TemplateValueParameterDefault:                     = ConditionalExpression                                TemplateAliasParameter:                    alias Identifier                    alias Identifier TemplateAliasParameterSpecialization                    alias Identifier TemplateAliasParameterDefault                    alias Identifier TemplateAliasParameterSpecialization TemplateAliasParameterDefault                                TemplateAliasParameterSpecialization:                     : Type                                TemplateAliasParameterDefault:                     = Type                                TemplateTupleParameter:                    Identifier ...                无论模板是否被最终实例化,模板声明 的过程体在语法上必须是正确的。语义分析延迟到模板实例化时进行。模板有自己的作用域,模板过程体中可以包括类、结构、类型、枚举、变量、函数或者其它模板。        模板参数可以是类型、值或者符号,或者tuple。可以使用任何类型。值参数必须是整数型,浮点指针型,字符串型,在特化时它们必须被解析为整数常量,浮点指针常量,null或者字符串文字量。符号可以是任何非局部符号。        Tuples are a sequence of 0 or more types, values or symbols.        模板参数特化将值或类型约束为 模板参数 可以接受的值或类型。        模板参数默认值用在不提供 模板参数 时。Explicit Template Instantiation        Templates are explicitly instantiated with:        QUOTE:                                TemplateInstance:                    TemplateIdentifer !( TemplateArgumentList )                                TemplateArgumentList:                    TemplateArgument                    TemplateArgument , TemplateArgumentList                                TemplateArgument:                    Type                    AssignExpression                    Symbol                一旦被实例化,位于模板内的声明,称做模板成员,就位于 TemplateInstance 作用域内:( 本文出处: http://www.d-programming-language-china.org )        [Copy to clipboard] [ - ]CODE:                                template TFoo(T) { alias T* t; }                ...                TFoo!(int).t x;        // 声明 x 为 int* 类型                模板实例化可以有别名:        [Copy to clipboard] [ - ]CODE:                                template TFoo(T) { alias T* t; }                alias TFoo!(int) abc;                abc.t x;            // 声明 x 为 int* 类型                一个 模板声明 拥有相同 模板参数列表 的多个实例,在隐式转换前,将引用相同的实例。例如:        [Copy to clipboard] [ - ]CODE:                                template TFoo(T) { T f; }                alias TFoo(int) a;                alias TFoo(int) b;                ...                a.f = 3;                assert(b.f == 3);        // a 和 b 引用相同的 TFoo 实例                即使 模板实例 位于不同的模块中,这条规则也成立。        Even if template arguments are implicitly converted to the same template parameter type, they still refer to different instances:        [Copy to clipboard] [ - ]CODE:                                struct TFoo(int x) { }                static assert(is(TFoo!(3) == TFoo!(2 + 1)));    // 3 and 2+1 are both 3 of type int                static assert(!is(TFoo!(3) == TFoo!(3u)));    // 3u and 3 are different types                如果声明了拥有多个相同 模板标志符 的模板,并且它们参数个数不同或者采用不同的特化,那么它们不同。( 本文出处: http://www.d-programming-language-china.org )        例如,一个简单的泛型复制函数可以是这个样子:        [Copy to clipboard] [ - ]CODE:                                template TCopy(T)                {                    void copy(out T to, T from)                    {                        to = from;                    }                }                在使用模板之前,必须先使用具体的类型将其实例化:        [Copy to clipboard] [ - ]CODE:                                int i;                TCopy!(int).copy(i, 3);        Instantiation Scope实例化作用域        模板实例 总是在声明 模板声明 的作用域内执行,另外声明的模板参数被看作它们所推出的类型的别名。        例如:                -------- module a ---------        [Copy to clipboard] [ - ]CODE:                                template TFoo(T) { void bar() { func(); } }                        -------- module b ---------        [Copy to clipboard] [ - ]CODE:                                import a;                void func() { }                alias TFoo!(int) f;    // 错误:func 没有在模块 a 内定义                以及:                -------- module a ---------        [Copy to clipboard] [ - ]CODE:                                template TFoo(T) { void bar() { func(1); } }                void func(double d) { }                        -------- module b ---------        [Copy to clipboard] [ - ]CODE:                                import a;                                void func(int i) { }                alias TFoo!(int) f;                ...                f.bar();            // 将调用 a.func(double)                模板参数 的特化和默认值将在 模板声明 的作用域内估值。( 本文出处: http://www.d-programming-language-china.org )Argument Deduction参数推导        采用比较对应的模板参数(template parameter)和模板实参(template argument)的方法,模板实例中的模板参数的类型被推倒出来。        对于每个模板参数,按照下面的顺序逐条应用规则直到每个参数的类型都被推倒出来:        如果参数没有指定一个特化,参数的类型被设为指定的模板实参。        如果类型特化依赖于一个类型参数,这个参数的类型就被设为与那个类型实参对应的类型。        如果在检查了所有类型实参之后还有类型参数没有被分配类型,它们就会被分配给在 模板参数列表 中位于相同位置的模板实参。        如果应用上述规则之后,还不能做到每个模板参数都精确的对应唯一一个类型,那么就被视为错误。        例如:        [Copy to clipboard] [ - ]CODE:                                template TFoo(T) { }                alias TFoo!(int) Foo1;        // (1) T is deduced to be int                alias TFoo!(char*) Foo2;    // (1) T is deduced to be char*                                template TBar(T : T*) { }                alias TBar!(char*) Foo3;    // (2) T is deduced to be char                                template TAbc(D, U : D[]) { }                alias TAbc!(int, int[]) Bar1;    // (2) D is deduced to be int, U is int[]                alias TAbc!(char, int[]) Bar2;    // (4) error, D is both char and int                                template TDef(D : E*, E) { }                alias TDef!(int*, int) Bar3;    // (1) E is int                                // (3) D is int*                Deduction from a specialization can provide values for more than one parameter:( 本文出处: http://www.d-programming-language-china.org )        [Copy to clipboard] [ - ]CODE:                                template Foo(T: T[U], U)                {                    ...                }                                Foo!(int[long])    // instantiates Foo with T set to int, U set to long                当考虑匹配时,一个类被认为可以匹配任何父类或接口:        [Copy to clipboard] [ - ]CODE:                                class A { }                class B : A { }                                template TFoo(T : A) { }                alias TFoo!(B) Foo4;        // (3) T is B                                template TBar(T : U*, U : A) { }                alias TBar!(B*, B) Foo5;    // (2) T is B*                                // (3) U is B        Value Parameters值参数        这个模板例子中,指定了一个为 10 的值参数:        [Copy to clipboard] [ - ]CODE:                                template foo(U : int, int T : 10)                {                    U x = T;                }                                void main()                {                    assert(foo!(int, 10).x == 10);                }        Specialization特化        模板可以通过在模板参数之后指定一个“:”和一个特化类型来将模板特化为使用某些指定的实参类型。例如:        [Copy to clipboard] [ - ]CODE:                                template TFoo(T)    { ... }     // #1                template TFoo(T : T[])    { ... }     // #2                template TFoo(T : char) { ... }     // #3                template TFoo(T,U,V)    { ... }     // #4                                alias TFoo!(int) foo1;            // 实例化 #1                alias TFoo!(double[]) foo2;        // 实例化 #2 ,其中 T 为 double                alias TFoo!(char) foo3;        // 实例化 #3                alias TFoo!(char, int) fooe;        // 错误,实参个数不匹配                alias TFoo!(char, int, int) foo4;     // 实例化 #4                当进行模板实例化时,会挑选匹配 模板参数列表 的特化度最高的模板。决定那个模板更为特化的方式同 C++ 处理偏序规则的方式相同。如果结果是模棱两可的,就是错误。Alias Parameters别名参数        别名参数使模板能够使用任何 D 符号参数化,包括全局名称、类型名称、模板名称以及模板实例名称。这是 C++ 中将模板作为模板参数的做法的超集。( 本文出处: http://www.d-programming-language-china.org )        全局名        [Copy to clipboard] [ - ]CODE:                                int x;                                template Foo(alias X)                {                    static int* p = &X;                }                                void test()                {                    alias Foo!(x) bar;                    *bar.p = 3;        // set x to 3                    static int y;                    alias Foo!(y) abc;                    *abc.p = 3;        // set y to 3                }                类型名        [Copy to clipboard] [ - ]CODE:                                class Foo                {                    static int p;                }                                template Bar(alias T)                {                    alias T.p q;                }                                void test()                {                    alias Bar!(Foo) bar;                    bar.q = 3;        // 将 Foo.p 设置为 3                }                模块名        [Copy to clipboard] [ - ]CODE:                                import std.string;                                template Foo(alias X)                {                    alias X.toString y;                }                                void test()                {                    alias Foo!(std.string) bar;                    bar.y(3);        // 调用 std.string.toString(3)                }                模板名        [Copy to clipboard] [ - ]CODE:                                int x;                                template Foo(alias X)                {                    static int* p = &X;                }                                template Bar(alias T)                {                    alias T!(x) abc;                }                                void test()                {                    alias Bar!(Foo) bar;                    *bar.abc.p = 3;    // sets x to 3                }                模板别名        [Copy to clipboard] [ - ]CODE:                                int x;                                template Foo(alias X)                {                    static int* p = &X;                }                                template Bar(alias T)                {                    alias T.p q;                }                                void test()                {                    alias Foo!(x) foo;                    alias Bar!(foo) bar;                    *bar.q = 3;        // sets x to 3                }        Template Parameter Default Values模板参数默认值        右端的模板参数(从最右端的那个开始向左连续的带有默认值的那些参数)可以有默认值:        [Copy to clipboard] [ - ]CODE:                                template Foo(T, U = int) { ... }                Foo!(uint,long);         // 实例化:T 为 uint ,U 为 long                Foo!(uint);         // 实例化:T 为 uint ,U 为 int                                template Foo(T, U = T*) { ... }                Foo!(uint);         // 实例化:T 为 uint ,U 为 uint*        Implicit Template Properties隐式模板属性        如果模板有且只有一个成员,并且这个成员和模板同名的话,这个成员就被认为引用的是一个模板实例:        [Copy to clipboard] [ - ]CODE:                                template Foo(T)                {                    T Foo;        // 声明变量 Foo 为类型 T                }                                void test()                {                    Foo!(int) = 6;    // 代替 Foo!(int).Foo                }        Tuple Parameters        If the last template parameter in the TemplateParameterList is declared as a TemplateTupleParameter, it is a match with any trailing template arguments. The sequence of arguments form a Tuple. A Tuple is not a type, an expression, or a symbol. It is a sequence of any mix of types, expressions or symbols.        A Tuple whose elements consist entirely of types is called a TypeTuple. A Tuple whose elements consist entirely of expressions is called an ExpressionTuple.        A Tuple can be used as an argument list to instantiate another template, or as the list of parameters for a function.( 本文出处: http://www.d-programming-language-china.org )        [Copy to clipboard] [ - ]CODE:                                template Print(A ...)                {                    void print()                    {                        writefln("args are ", A);                    }                }                                template Write(A ...)                {                    void write(A a)    // A is a TypeTuple                            // a is an ExpressionTuple                    {                        writefln("args are ", a);                    }                }                                void main()                {                    Print!(1,'a',6.8).print();                // prints: args are 1a6.8                    Write!(int, char, double).write(1, 'a', 6.8); // prints: args are 1a6.8                }                Template tuples can be deduced from the types of the trailing parameters of an implicitly instantiated function template:        [Copy to clipboard] [ - ]CODE:                                template Foo(T, R...)                {                    void Foo(T t, R r)                    {                        writefln(t);                        static if (r.length)    // if more arguments                        Foo(r);        // do the rest of the arguments                    }                }                                void main()                {                    Foo(1, 'a', 6.8);                }                prints:        QUOTE:                                1                a                6.8                The tuple can also be deduced from the type of a delegate or function parameter list passed as a function argument:        [Copy to clipboard] [ - ]CODE:                                /* R is return type                 * A is first argument type                 * U is TypeTuple of rest of argument types                 */                R delegate(U) Curry(R, A, U...)(R delegate(A, U) dg, A arg)                {                    struct Foo                    {                    typeof(dg) dg_m;                    typeof(arg) arg_m;                                    R bar(U u)                    {                        return dg_m(arg_m, u);                    }                    }                                    Foo* f = new Foo;                    f.dg_m = dg;                    f.arg_m = arg;                    return &f.bar;                }                                void main()                {                    int plus(int x, int y, int z)                    {                    return x + y + z;                    }                                    auto plus_two = Curry(&plus, 2);                    printf("%d\n", plus_two(6, 8));    // prints 16                }                The number of elements in a Tuple can be retrieved with the .length property. The nth element can be retrieved by indexing the Tuple with [n], and sub tuples can be created with the slicing syntax.        Tuples are static compile time entities, there is no way to dynamically change, add, or remove elements.( 本文出处: http://www.d-programming-language-china.org )        If both a template with a tuple parameter and a template without a tuple parameter exactly match a template instantiation, the template without a TemplateTupleParameter is selected.Class Templates类模板        QUOTE:                                类模板声明:                    class 标志符( 模板参数列表) [父类{, 接口类}] 类过程体                                ClassTemplateDeclaration:                    class Identifier ( TemplateParameterList ) [SuperClass {, InterfaceClass }] ClassBody                如果一个模板声明且仅声明了一个成员,并且那个成员是一个同模板同名的类:        [Copy to clipboard] [ - ]CODE:                                template Bar(T)                {                    class Bar                    {                        T member;                    }                }                则同下面的声明语义等价,称作 类模板声明 :        [Copy to clipboard] [ - ]CODE:                                class Bar(T)                {                    T member;                }        Function Templates函数模版        If a template declares exactly one member, and that member is a function with the same name as the template:        QUOTE:                                FunctionTemplateDeclaration:                    类型标识符 (模版参数列表 ) ( 函数参数列表 ) 函数体                    Type Identifier ( TemplateParameterList ) ( FunctionParameterList ) FunctionBody                一个计算类型为T的平方的函数为:( 本文出处: http://www.d-programming-language-china.org )        [Copy to clipboard] [ - ]CODE:                                T Square(T)(T t)                {                    return t * t;                }                Function templates can be explicitly instantiated with a !(TemplateArgumentList):        [Copy to clipboard] [ - ]CODE:                                writefln("The square of %s is %s", 3, Square!(int)(3));                or implicitly, where the TemplateArgumentList is deduced from the types of the function arguments:        [Copy to clipboard] [ - ]CODE:                                writefln("The square of %s is %s", 3, Square(3));    // T is deduced to be int                Function template type parameters that are to be implicitly deduced may not have specializations:        [Copy to clipboard] [ - ]CODE:                                void Foo(T : T*)(T t) { ... }                                int x,y;                Foo!(int*)(x);    // ok, T is not deduced from function argument                Foo(&y);    // error, T has specialization                Template arguments not implicitly deduced can have default values:        [Copy to clipboard] [ - ]CODE:                                void Foo(T, U=T*)(T t) { U p; ... }                                int x;                Foo(&x);    // T is int, U is int*        Recursive Templates递归模板        可以组合模板的各种特性来产生一些有趣的效果,例如在编译时对非平凡函数求值。例如,可以写一个计算阶乘的模板:( 本文出处: http://www.d-programming-language-china.org )        [Copy to clipboard] [ - ]CODE:                                template factorial(int n : 1)                {                    enum { factorial = 1 }                }                                template factorial(int n)                {                    enum { factorial = n* factorial!(n-1) }                }                                void test()                {                    writefln("%s", factorial!(4));    // prints 24                }        Limitations限制        模板不能用来给类添加非静态成员或函数。例如:        [Copy to clipboard] [ - ]CODE:                                class Foo                {                    template TBar(T)                    {                    T xx;                // 错误                    int func(T) { ... }        // 错误                                    static T yy;            // Ok                    static int func(T t, int y) { ... }     // Ok                    }                }                不能在函数内部声明模板。( lastupdate:20070426 最新文章请访问http://www.d-programming-language-china.org )关于一大步成功社区:yidabu提倡在交流中学习,在分享中提高收集感兴趣的知识,写下心得,通过网络与别人一起分享理解一点就实践一步,收获什么就分享什么,成功就是这样一点点一步步累积起来的网络只是一个工具,只有自己身心提高才是实实在在的。d-programming-language-china.org为大家提供一个学习交流各种知识的平台
页: [1]
查看完整版本: 19 D语言 模板 Templates