digitalmars.D - Question about explicit template instantiation
- Edward Diener (27/27) Feb 09 2008 I am working my way throught the pdf documentation ( 1.0 ) regarding
- Tyro[a.c.edwards] (25/59) Feb 09 2008 The problem here is that you are misconstruing templates to be classes.
- Edward Diener (20/78) Feb 10 2008 I understand what a template is and that the instantiation of a template...
- Janice Caron (28/35) Feb 10 2008 Alas no. You can omit the brackets, but you cannot omit the word
- Edward Diener (7/57) Feb 10 2008 A template being a namespace in D is certainly different from C++.
- Janice Caron (47/53) Feb 10 2008 That's /exactly/ the way that D works. With CLASS templates, D works
- Edward Diener (15/86) Feb 10 2008 The explanation for Class Templates in the D1 doc does not explain
- Jesse Phillips (9/106) Feb 10 2008 Well, you can't write A!(int) x; unless you precede it with alias.
- Jesse Phillips (6/119) Feb 10 2008 Hold on I just made a type out of A!(int) so
- Janice Caron (26/27) Feb 10 2008 Not so.
- Janice Caron (6/16) Feb 10 2008 Whoa! Big mistake! Sorry. Typo. Got that wrong. Don't want to confuse
- Janice Caron (18/25) Feb 10 2008 Sometimes, but only in special case. If you don't specify a member of
- Edward Diener (2/43) Feb 11 2008 Thanks for the explanation !
- Tyro[a.c.edwards] (11/33) Feb 10 2008 Actually, I said a "template is NOT a type." However, I don't tink I
- Jarrett Billingsley (39/67) Feb 10 2008 Aliases are a superset of the C/C++ typedef. An alias is much more gene...
- Edward Diener (10/94) Feb 10 2008 This is utterly confusing to me coming from C++. Instantiating templates...
- bearophile (4/6) Feb 10 2008 The situation is rather simple. A D template is a section of code that i...
- Jarrett Billingsley (57/60) Feb 10 2008 As Janice said, instantiating a template creates a namespace in which th...
- Edward Diener (2/84) Feb 11 2008 Thanks for the explanation !
I am working my way throught the pdf documentation ( 1.0 ) regarding templates in D and in the topic about explicit template instantiation and I came across the lines below, which have me stumped: ---------------------------------------------------------------- A template instantiation can be aliased: template TFoo(T) { alias T* t; } alias TFoo!(int) abc; abc.t x; // declare x to be of type int* Multiple instantiations of a TemplateDeclaration with the same TemplateArgumentList, before implicit conversions, all will refer to the same instantiation. For example: template TFoo(T) { T f; } alias TFoo!(int) a; alias TFoo!(int) b; ... a.f = 3; assert(b.f == 3); // a and b refer to the same instance of TFoo This is true even if the TemplateInstances are done in different modules. ---------------------------------------------------------------- My confusion with the above is that an alias, when referring to a type, is the equivalent of a C++ typedef AFAICS. So 'a' and 'b' above are types ( because the instantiated template is a type ) and then I see the 'a.f=3' line followed by the 'assert(b.f == 3)' line and I can not understand how a type can be used in either expression. I am also assuming that the line beginning with "Multiple instantiations of a..." only mean that the 'a' and 'b' refer to the same type, but perhaps I have missed something in this explanation.
Feb 09 2008
Edward Diener さんは書きました:I am working my way throught the pdf documentation ( 1.0 ) regarding templates in D and in the topic about explicit template instantiation and I came across the lines below, which have me stumped: ---------------------------------------------------------------- A template instantiation can be aliased: template TFoo(T) { alias T* t; } alias TFoo!(int) abc; abc.t x; // declare x to be of type int* Multiple instantiations of a TemplateDeclaration with the same TemplateArgumentList, before implicit conversions, all will refer to the same instantiation. For example: template TFoo(T) { T f; } alias TFoo!(int) a; alias TFoo!(int) b; ... a.f = 3; assert(b.f == 3); // a and b refer to the same instance of TFoo This is true even if the TemplateInstances are done in different modules. ---------------------------------------------------------------- My confusion with the above is that an alias, when referring to a type, is the equivalent of a C++ typedef AFAICS. So 'a' and 'b' above are types ( because the instantiated template is a type ) and then I see the 'a.f=3' line followed by the 'assert(b.f == 3)' line and I can not understand how a type can be used in either expression. I am also assuming that the line beginning with "Multiple instantiations of a..." only mean that the 'a' and 'b' refer to the same type, but perhaps I have missed something in this explanation.The problem here is that you are misconstruing templates to be classes. Templates, like classes and other types, can be aliased, however since a template is not a type you couldn't use TFoo!(int) to declare a variable. This also applies to the derived aliases 'a' and 'b'. The templated class however, is a different story. Take the following code snipet for example: class Bar(T) { T f; } alias bar!(int) y; alias bar!(int) z; Here Bar(T) is a class, therefore Bar!(int) is a class instanciation: a type. Hence, the aliases, 'y' and 'z' are also types. Any attempts to use them as with the previous example, will result in an error. y.f = 3; // Error y is an instanciated class assert(z.f == 3); // Error y is an instanciated class Proper usage in this case is the same as any other class: y Y; // OK Y.f = 3; // Error memory not yet allocated for Y Y = new y; // OK Y.f = 3; // OK assert(Y.f == 3); //OK Hope that helps somewhat!
Feb 09 2008
Tyro[a.c.edwards] wrote:Edward Diener さんは書きました:I understand what a template is and that the instantiation of a template is a type ( class ). So in the example above 'a' and 'b' are aliases for types, ie. typedef in C++. Therefore the statements "a.f = 3;" and 'assert(b.f == 3);" made no sense to me. But I think I understand them now, but hopefully someone will clarify things for me. It seems in D one can instantiate a temporary object from a type which has a default constructor simply by using the type, whereas in C++ one must use the type followed by '()'. So whereas if X were a class with a default constructor with the data member Y, in C++ one would use 'X().Y' to access the temporary's Y data member while in D it appears one can use 'X.Y' to access the temporary's data member. The previous explanation is the only way I can make sense of the two statements above which led to my OP.I am working my way throught the pdf documentation ( 1.0 ) regarding templates in D and in the topic about explicit template instantiation and I came across the lines below, which have me stumped: ---------------------------------------------------------------- A template instantiation can be aliased: template TFoo(T) { alias T* t; } alias TFoo!(int) abc; abc.t x; // declare x to be of type int* Multiple instantiations of a TemplateDeclaration with the same TemplateArgumentList, before implicit conversions, all will refer to the same instantiation. For example: template TFoo(T) { T f; } alias TFoo!(int) a; alias TFoo!(int) b; ... a.f = 3; assert(b.f == 3); // a and b refer to the same instance of TFoo This is true even if the TemplateInstances are done in different modules. ---------------------------------------------------------------- My confusion with the above is that an alias, when referring to a type, is the equivalent of a C++ typedef AFAICS. So 'a' and 'b' above are types ( because the instantiated template is a type ) and then I see the 'a.f=3' line followed by the 'assert(b.f == 3)' line and I can not understand how a type can be used in either expression. I am also assuming that the line beginning with "Multiple instantiations of a..." only mean that the 'a' and 'b' refer to the same type, but perhaps I have missed something in this explanation.The problem here is that you are misconstruing templates to be classes. Templates, like classes and other types, can be aliased, however since a template is not a type you couldn't use TFoo!(int) to declare a variable. This also applies to the derived aliases 'a' and 'b'.The templated class however, is a different story. Take the following code snipet for example: class Bar(T) { T f; } alias bar!(int) y; alias bar!(int) z; Here Bar(T) is a class, therefore Bar!(int) is a class instanciation: a type. Hence, the aliases, 'y' and 'z' are also types. Any attempts to use them as with the previous example, will result in an error. y.f = 3; // Error y is an instanciated class assert(z.f == 3); // Error y is an instanciated classWhat I quoted in my OP was all directly from the documentation, not anything I made up. Somehow you think that the lines: a.f = 3; assert(b.f == 3); // a and b refer to the same instance of TFoo were inserted by me. No ! They were in the doc and they appeared to be incorrect, and I wanted an explanation for them.
Feb 10 2008
On 10/02/2008, Edward Diener <eddielee_no_spam_here tropicsoft.com> wrote:But I think I understand them now, but hopefully someone will clarify things for me. It seems in D one can instantiate a temporary object from a type which has a default constructor simply by using the type, whereas in C++ one must use the type followed by '()'. So whereas if X were a class with a default constructor with the data member Y, in C++ one would use 'X().Y' to access the temporary's Y data member while in D it appears one can use 'X.Y' to access the temporary's data member.Alas no. You can omit the brackets, but you cannot omit the word "new". Thus, it would be either new X().Y or (new X).Y A template is not necessarily a class. You can have template classes, but not all templates are classes. You can also have template functions, but not all templates are functions. The most general statement would probably be that a template is a namespace. Thus: template MyNamespace(T) { int x; } generates a different namespace for each different type of T. So in the above example, x is a global variable, not a member variable, within MyNamespace!(T) for some T. Therefore: MyNamesspace!(int).x is a different variable from MyNamespace!(double).x because the Ts are different. If I choose to save typing by writing: alias MyNamespace!(int) A; alias MyNamespace!(double) B; then A.x and B.x would still be different global variables. However, if I later write alias MyNamespace!(int) C; then C refers to the /same/ namespace as A, and hence A.x and C.x are the exact same global variable.
Feb 10 2008
Janice Caron wrote:On 10/02/2008, Edward Diener <eddielee_no_spam_here tropicsoft.com> wrote:Understood. I forgot all non-struct classes must be in GC memory.But I think I understand them now, but hopefully someone will clarify things for me. It seems in D one can instantiate a temporary object from a type which has a default constructor simply by using the type, whereas in C++ one must use the type followed by '()'. So whereas if X were a class with a default constructor with the data member Y, in C++ one would use 'X().Y' to access the temporary's Y data member while in D it appears one can use 'X.Y' to access the temporary's data member.Alas no. You can omit the brackets, but you cannot omit the word "new". Thus, it would be either new X().Y or (new X).YA template is not necessarily a class. You can have template classes, but not all templates are classes. You can also have template functions, but not all templates are functions. The most general statement would probably be that a template is a namespace. Thus: template MyNamespace(T) { int x; }A template being a namespace in D is certainly different from C++.generates a different namespace for each different type of T. So in the above example, x is a global variable, not a member variable, within MyNamespace!(T) for some T. Therefore: MyNamesspace!(int).x is a different variable from MyNamespace!(double).x because the Ts are different. If I choose to save typing by writing: alias MyNamespace!(int) A; alias MyNamespace!(double) B; then A.x and B.x would still be different global variables. However, if I later write alias MyNamespace!(int) C; then C refers to the /same/ namespace as A, and hence A.x and C.x are the exact same global variable.This is confusing to me coming from C++. In C++ instantiating a class template produces a type. Is that not the way D works ? If not, what does instantiating a template produce in D and, if it does not produce a type, how does one instantiate a template which does produce a type in D ?
Feb 10 2008
On 10/02/2008, Edward Diener <eddielee_no_spam_here tropicsoft.com> wrote:template MyNamespace(T) { int x; }This is confusing to me coming from C++. In C++ instantiating a class template produces a type. Is that not the way D works ?That's /exactly/ the way that D works. With CLASS templates, D works just like C++. No problem. Compare: c++ template<class T> class A { int x; }; A<int> a1; A<double> a2; and the D equivalent: class A(T) { int x; } auto a1 = new A!(int); auto a2 = new A!(double); They're exactly the same, except that D has nicer syntax. I don't think /class/ templates are confusing you at all! I think what's confusing you is that in D you can have /namespace/ templates, which don't exist in C++. Let me make an approximate C++ translation. Here's the D again: template A(T) { int x; } That is roughly equivalent to, in C++ namespace A_int { int x; } namespace A_float { int x; } namespace A_double { int x; } ...and so on for every imaginable type. Now it should be clear to you that A_int::x is a different variable from A_float::x, yes? For a namespaces to be "instantiated" just means that the corresponding chunk of code is there. To be /not/ instantiated would mean that it isn't there - which is just as well really, because there are in infinite number of possible types! To instantiate a namespace template, you only have to refer to it. I doesn't matter how. Clear?
Feb 10 2008
Janice Caron wrote:On 10/02/2008, Edward Diener <eddielee_no_spam_here tropicsoft.com> wrote:The explanation for Class Templates in the D1 doc does not explain anything at all. That is why I assumed the template A(T) notation referred to the equivalent of the C++ class template.template MyNamespace(T) { int x; }This is confusing to me coming from C++. In C++ instantiating a class template produces a type. Is that not the way D works ?That's /exactly/ the way that D works. With CLASS templates, D works just like C++. No problem. Compare: c++ template<class T> class A { int x; }; A<int> a1; A<double> a2; and the D equivalent: class A(T) { int x; } auto a1 = new A!(int); auto a2 = new A!(double); They're exactly the same, except that D has nicer syntax. I don't think /class/ templates are confusing you at all! I think what's confusing you is that in D you can have /namespace/ templates, which don't exist in C++.Let me make an approximate C++ translation. Here's the D again: template A(T) { int x; } That is roughly equivalent to, in C++ namespace A_int { int x; } namespace A_float { int x; } namespace A_double { int x; } ...and so on for every imaginable type. Now it should be clear to you that A_int::x is a different variable from A_float::x, yes?Now I understand. I was surely fooled by the doc.For a namespaces to be "instantiated" just means that the corresponding chunk of code is there. To be /not/ instantiated would mean that it isn't there - which is just as well really, because there are in infinite number of possible types! To instantiate a namespace template, you only have to refer to it. I doesn't matter how. Clear?I think so. Instantiating a namespace template merely puts the equivalent code, with the types you instantiate it with substituted each time those types are referred to in the namespace, directly into your source. I still do not understand what the object used for the instantiation is. In your example above what is: A!(int) ? Is it some kind of namespace ? Can I say: A!(int) x; ? If so, what is x ?
Feb 10 2008
On Sun, 10 Feb 2008 17:31:36 -0500, Edward Diener wrote:Janice Caron wrote:Well, you can't write A!(int) x; unless you precede it with alias. If we have: template A(T) { T f; } I'm new to templates so I don't really know how to say what A!(int) is, but I think a good way to think of it as declaring an instance of a struct. struct B { int f }; where B = A!(int);On 10/02/2008, Edward Diener <eddielee_no_spam_here tropicsoft.com> wrote:The explanation for Class Templates in the D1 doc does not explain anything at all. That is why I assumed the template A(T) notation referred to the equivalent of the C++ class template.template MyNamespace(T) { int x; }This is confusing to me coming from C++. In C++ instantiating a class template produces a type. Is that not the way D works ?That's /exactly/ the way that D works. With CLASS templates, D works just like C++. No problem. Compare: c++ template<class T> class A { int x; }; A<int> a1; A<double> a2; and the D equivalent: class A(T) { int x; } auto a1 = new A!(int); auto a2 = new A!(double); They're exactly the same, except that D has nicer syntax. I don't think /class/ templates are confusing you at all! I think what's confusing you is that in D you can have /namespace/ templates, which don't exist in C++.Let me make an approximate C++ translation. Here's the D again: template A(T) { int x; } That is roughly equivalent to, in C++ namespace A_int { int x; } namespace A_float { int x; } namespace A_double { int x; } ...and so on for every imaginable type. Now it should be clear to you that A_int::x is a different variable from A_float::x, yes?Now I understand. I was surely fooled by the doc.For a namespaces to be "instantiated" just means that the corresponding chunk of code is there. To be /not/ instantiated would mean that it isn't there - which is just as well really, because there are in infinite number of possible types! To instantiate a namespace template, you only have to refer to it. I doesn't matter how. Clear?I think so. Instantiating a namespace template merely puts the equivalent code, with the types you instantiate it with substituted each time those types are referred to in the namespace, directly into your source. I still do not understand what the object used for the instantiation is. In your example above what is: A!(int) ? Is it some kind of namespace ? Can I say: A!(int) x; ? If so, what is x ?
Feb 10 2008
On Sun, 10 Feb 2008 22:58:51 +0000, Jesse Phillips wrote:On Sun, 10 Feb 2008 17:31:36 -0500, Edward Diener wrote:Hold on I just made a type out of A!(int) so A!(int) would be equivalent to struct B { int f }; B a; where B a is A!(int);Janice Caron wrote:Well, you can't write A!(int) x; unless you precede it with alias. If we have: template A(T) { T f; } I'm new to templates so I don't really know how to say what A!(int) is, but I think a good way to think of it as declaring an instance of a struct. struct B { int f }; where B = A!(int);On 10/02/2008, Edward Diener <eddielee_no_spam_here tropicsoft.com> wrote:The explanation for Class Templates in the D1 doc does not explain anything at all. That is why I assumed the template A(T) notation referred to the equivalent of the C++ class template.template MyNamespace(T) { int x; }This is confusing to me coming from C++. In C++ instantiating a class template produces a type. Is that not the way D works ?That's /exactly/ the way that D works. With CLASS templates, D works just like C++. No problem. Compare: c++ template<class T> class A { int x; }; A<int> a1; A<double> a2; and the D equivalent: class A(T) { int x; } auto a1 = new A!(int); auto a2 = new A!(double); They're exactly the same, except that D has nicer syntax. I don't think /class/ templates are confusing you at all! I think what's confusing you is that in D you can have /namespace/ templates, which don't exist in C++.Let me make an approximate C++ translation. Here's the D again: template A(T) { int x; } That is roughly equivalent to, in C++ namespace A_int { int x; } namespace A_float { int x; } namespace A_double { int x; } ...and so on for every imaginable type. Now it should be clear to you that A_int::x is a different variable from A_float::x, yes?Now I understand. I was surely fooled by the doc.For a namespaces to be "instantiated" just means that the corresponding chunk of code is there. To be /not/ instantiated would mean that it isn't there - which is just as well really, because there are in infinite number of possible types! To instantiate a namespace template, you only have to refer to it. I doesn't matter how. Clear?I think so. Instantiating a namespace template merely puts the equivalent code, with the types you instantiate it with substituted each time those types are referred to in the namespace, directly into your source. I still do not understand what the object used for the instantiation is. In your example above what is: A!(int) ? Is it some kind of namespace ? Can I say: A!(int) x; ? If so, what is x ?
Feb 10 2008
On 10/02/2008, Jesse Phillips <jessekphillips gmail.com> wrote:Well, you can't write A!(int) x; unless you precede it with alias.Not so. template A(T) { int A; } A!(double) = 42; writefln(A!(double)); // prints 42 writefln(typeof(A!(double))); // prints double In this example, A!(double) is short for A!(double).A, which in an int, so we can assign a value to it and print it. But template A(T) { struct A { int x; } } In /this/ example A!(T).A is a type. (And hence, so is A!(T)). Observe that there's a neater way of writing that though. We can abbreviate that to struct A(T) { int x; }
Feb 10 2008
On 10/02/2008, Janice Caron <caron800 googlemail.com> wrote:On 10/02/2008, Jesse Phillips <jessekphillips gmail.com> wrote:Whoa! Big mistake! Sorry. Typo. Got that wrong. Don't want to confuse anyone! Let's try again... writefln(typeof(A!(double))); // prints int That's better! Phew!Well, you can't write A!(int) x; unless you precede it with alias.Not so. template A(T) { int A; } A!(double) = 42; writefln(A!(double)); // prints 42 writefln(typeof(A!(double))); // prints double
Feb 10 2008
On 10/02/2008, Edward Diener <eddielee_no_spam_here tropicsoft.com> wrote:I still do not understand what the object used for the instantiation is. In your example above what is: A!(int) ? Is it some kind of namespace ?Yes. It is exactly a namespace.Can I say: A!(int) x; ?Sometimes, but only in special case. If you don't specify a member of the namespace, then the compiler will /assume/ a member whose name is the same as that of the template. So, if we have: template A(T) { int A; } then A!(int) x; would be shorthand for A!(int).A x; But if there wasn't an A in the namespace, then it wouldn't compile. That little "trick" is really, really useful, because it can make for a lot less typing. So - in general - A!(T) with no member, is the same thing as A!(T).A, if A!(T).A exists. /What/ is it, depends. It's whatever A!(T).A is.
Feb 10 2008
Janice Caron wrote:On 10/02/2008, Edward Diener <eddielee_no_spam_here tropicsoft.com> wrote:Thanks for the explanation !I still do not understand what the object used for the instantiation is. In your example above what is: A!(int) ? Is it some kind of namespace ?Yes. It is exactly a namespace.Can I say: A!(int) x; ?Sometimes, but only in special case. If you don't specify a member of the namespace, then the compiler will /assume/ a member whose name is the same as that of the template. So, if we have: template A(T) { int A; } then A!(int) x; would be shorthand for A!(int).A x; But if there wasn't an A in the namespace, then it wouldn't compile. That little "trick" is really, really useful, because it can make for a lot less typing. So - in general - A!(T) with no member, is the same thing as A!(T).A, if A!(T).A exists. /What/ is it, depends. It's whatever A!(T).A is.
Feb 11 2008
Edward Diener さんは書きました:Tyro[a.c.edwards] wrote:[snip]Edward Diener さんは書きました:I understand what a template is and that the instantiation of a template is a type ( class ). So in the example above 'a' and 'b' are aliases for types, ie. typedef in C++. Therefore the statements "a.f = 3;" and 'assert(b.f == 3);" made no sense to me.Actually, I said a "template is NOT a type." However, I don't tink I have enought experience in either English or D to explain thing to you so I'll stop before embarrasing myself further.But I think I understand them now, but hopefully someone will clarify things for me. It seems in D one can instantiate a temporary object from a type which has a default constructor simply by using the type, whereas in C++ one must use the type followed by '()'. So whereas if X were a class with a default constructor with the data member Y, in C++ one would use 'X().Y' to access the temporary's Y data member while in D it appears one can use 'X.Y' to access the temporary's data member.Unfortunately I don't think you undersand... see previous comment.What I quoted in my OP was all directly from the documentation, not anything I made up. Somehow you think that the lines: a.f = 3; assert(b.f == 3); // a and b refer to the same instance of TFoo were inserted by me. No ! They were in the doc and they appeared to be incorrect, and I wanted an explanation for them.No, actually I went to the document that you were reading, read a little further down the page and took an example of a CLASS template and used it to attempt an explanation. Hopefully, someone will be able to assist you. Good luck! Andrew
Feb 10 2008
"Edward Diener" <eddielee_no_spam_here tropicsoft.com> wrote in message news:foleie$67q$1 digitalmars.com...I am working my way throught the pdf documentation ( 1.0 ) regarding templates in D and in the topic about explicit template instantiation and I came across the lines below, which have me stumped: ---------------------------------------------------------------- A template instantiation can be aliased: template TFoo(T) { alias T* t; } alias TFoo!(int) abc; abc.t x; // declare x to be of type int* Multiple instantiations of a TemplateDeclaration with the same TemplateArgumentList, before implicit conversions, all will refer to the same instantiation. For example: template TFoo(T) { T f; } alias TFoo!(int) a; alias TFoo!(int) b; ... a.f = 3; assert(b.f == 3); // a and b refer to the same instance of TFoo This is true even if the TemplateInstances are done in different modules. ---------------------------------------------------------------- My confusion with the above is that an alias, when referring to a type, is the equivalent of a C++ typedef AFAICS. So 'a' and 'b' above are types ( because the instantiated template is a type ) and then I see the 'a.f=3' line followed by the 'assert(b.f == 3)' line and I can not understand how a type can be used in either expression.Aliases are a superset of the C/C++ typedef. An alias is much more general, allowing you to not only rename types, but more generally, create a new symbol (name) that refers to another symbol. This way, you can alias types, template instantiations, functions, methods, modules, etc. etc. What's happening here is that TFoo is not a type, and an instance of TFoo is not a type either. TFoo, when instantiated, is more like a namespace. It has a single variable, f. This is not a field or anything, it's just a variable. When you instantiate TFoo with a type, you basically declare a global variable TFoo!(T).f. So: template TFoo(T) { T f; } void foo() { alias TFoo!(int) a; a.f++; Stdout.formatln("{}", a.f); } void main() { foo(); foo(); } prints 1 and 2. Notice that even though 'a' was aliased inside foo(), it's kind of like a static variable. Contrast this with mixins, where the declarations are inserted at the instantiation location: void foo() { mixin TFoo!(int) a; a.f++; Stdout.formatln("{}", a.f); } This prints 1 and 1, since a.f is now basically a local variable.I am also assuming that the line beginning with "Multiple instantiations of a..." only mean that the 'a' and 'b' refer to the same type, but perhaps I have missed something in this explanation.a and b refer to the same *symbol*, yes. But instantiations of TFoo are not types.
Feb 10 2008
Jarrett Billingsley wrote:"Edward Diener" <eddielee_no_spam_here tropicsoft.com> wrote in message news:foleie$67q$1 digitalmars.com...Understood.I am working my way throught the pdf documentation ( 1.0 ) regarding templates in D and in the topic about explicit template instantiation and I came across the lines below, which have me stumped: ---------------------------------------------------------------- A template instantiation can be aliased: template TFoo(T) { alias T* t; } alias TFoo!(int) abc; abc.t x; // declare x to be of type int* Multiple instantiations of a TemplateDeclaration with the same TemplateArgumentList, before implicit conversions, all will refer to the same instantiation. For example: template TFoo(T) { T f; } alias TFoo!(int) a; alias TFoo!(int) b; ... a.f = 3; assert(b.f == 3); // a and b refer to the same instance of TFoo This is true even if the TemplateInstances are done in different modules. ---------------------------------------------------------------- My confusion with the above is that an alias, when referring to a type, is the equivalent of a C++ typedef AFAICS. So 'a' and 'b' above are types ( because the instantiated template is a type ) and then I see the 'a.f=3' line followed by the 'assert(b.f == 3)' line and I can not understand how a type can be used in either expression.Aliases are a superset of the C/C++ typedef. An alias is much more general, allowing you to not only rename types, but more generally, create a new symbol (name) that refers to another symbol. This way, you can alias types, template instantiations, functions, methods, modules, etc. etc.What's happening here is that TFoo is not a type, and an instance of TFoo is not a type either. TFoo, when instantiated, is more like a namespace. It has a single variable, f. This is not a field or anything, it's just a variable. When you instantiate TFoo with a type, you basically declare a global variable TFoo!(T).f. So: template TFoo(T) { T f; } void foo() { alias TFoo!(int) a; a.f++; Stdout.formatln("{}", a.f); } void main() { foo(); foo(); } prints 1 and 2. Notice that even though 'a' was aliased inside foo(), it's kind of like a static variable.This is utterly confusing to me coming from C++. Instantiating templates in C++ produce a type. If a template instantiation is not a type, what is it ? Also how does one produce a type from a template in D ?Contrast this with mixins, where the declarations are inserted at the instantiation location: void foo() { mixin TFoo!(int) a; a.f++; Stdout.formatln("{}", a.f); } This prints 1 and 1, since a.f is now basically a local variable.I will tackle mixins once I understand D templates, but I am now lost.Thanks for the information but I await your and Janice's response about what a template instantiation is. I admit I am lost now with D templates and the doc sure did not prepare me for whatever a template instantiation is supposed to be.I am also assuming that the line beginning with "Multiple instantiations of a..." only mean that the 'a' and 'b' refer to the same type, but perhaps I have missed something in this explanation.a and b refer to the same *symbol*, yes. But instantiations of TFoo are not types.
Feb 10 2008
Edward Diener:Thanks for the information but I await your and Janice's response about what a template instantiation is.The situation is rather simple. A D template is a section of code that is parametric in one or more types. Just like a function is a piece of code that is parametric on the value of some types (the situation isn't fully symmetric because in D types aren't first class values yet, but they are close enough for many purposes). Inside that section you can put what you want, types that depend of the template types, classes that are depends of the template types (that you can think as variables), etc. When you instantiate a type you give the value to those type variables, so you just define what types those "type variables" are, so you define real pieces of code, for functions, classes, etc, that you can take a pointer of, you can instantiate, you can call, etc. Before that, they are "virtual", generic, not even fully cheeked by the compiler. As time passes, D types become a bit more and more first class, that allows you to operate on them in more ways (at compile time). Bye, bearophile
Feb 10 2008
"Edward Diener" <eddielee_no_spam_here tropicsoft.com> wrote in message news:fonlr1$2krb$1 digitalmars.com...This is utterly confusing to me coming from C++. Instantiating templates in C++ produce a type. If a template instantiation is not a type, what is it ? Also how does one produce a type from a template in D ?As Janice said, instantiating a template creates a namespace in which the template parameters are replaced by the arguments given in the instantiation. C++'s templates are intrinsically bound to either classes or functions, and instantiating a template in C++ gets you either a class or a function. D's templates are more general; they simply declare a namespace in which one or more declarations can exist, all parameterized by the template's parameters. It might help to know that this: class A(T) { .. } is _exactly_ equivalent (and in fact turned into this by the compiler) to: template A(T) { class A { ... } } Why this works is because if a template contains exactly one declaration, and that declaration has the same name as the template, referring to the template instantiation refers to the symbol inside it. So: A!(int).A a; A!(int) b; // sugar for the previous line Function templates work similarly. void foo(T)() { ... } == template foo(T) { void foo() { } } So this function can be called either as foo!(int)() or as foo!(int).foo(). This extends to any kind of declaration. template A(T, U) { T t; U u; } template A(T) { // an alias is a declaration too. alias A!(T, T) A; } alias A!(int, float) one; // one.t is int, one.u is float // we don't have to say A!(char).A alias A!(char) two; // both two.t and two.u are char You can have more than one declaration in a template, but then the "automatic symbol use" magic stops happening.
Feb 10 2008
Jarrett Billingsley wrote:"Edward Diener" <eddielee_no_spam_here tropicsoft.com> wrote in message news:fonlr1$2krb$1 digitalmars.com...Thanks for the explanation !This is utterly confusing to me coming from C++. Instantiating templates in C++ produce a type. If a template instantiation is not a type, what is it ? Also how does one produce a type from a template in D ?As Janice said, instantiating a template creates a namespace in which the template parameters are replaced by the arguments given in the instantiation. C++'s templates are intrinsically bound to either classes or functions, and instantiating a template in C++ gets you either a class or a function. D's templates are more general; they simply declare a namespace in which one or more declarations can exist, all parameterized by the template's parameters. It might help to know that this: class A(T) { .. } is _exactly_ equivalent (and in fact turned into this by the compiler) to: template A(T) { class A { ... } } Why this works is because if a template contains exactly one declaration, and that declaration has the same name as the template, referring to the template instantiation refers to the symbol inside it. So: A!(int).A a; A!(int) b; // sugar for the previous line Function templates work similarly. void foo(T)() { ... } == template foo(T) { void foo() { } } So this function can be called either as foo!(int)() or as foo!(int).foo(). This extends to any kind of declaration. template A(T, U) { T t; U u; } template A(T) { // an alias is a declaration too. alias A!(T, T) A; } alias A!(int, float) one; // one.t is int, one.u is float // we don't have to say A!(char).A alias A!(char) two; // both two.t and two.u are char You can have more than one declaration in a template, but then the "automatic symbol use" magic stops happening.
Feb 11 2008