Re: Can't understand templates
Ah, now I see. In C++ we would also need to supply template parameters, but we'd put them before return type (templatetypename T getResponsePointT); in D we put them before the colon. Now I'm trying to write a specialization for Pair. It seems that this is the way to do it: Pair!(A, B) getResponse(A, B: Pair!(A, B))(string question) { auto a = getResponse!A( a); auto b = getResponse!B( b); return new Pair!(A, B)(a, b); } auto pair = getResponse!(Pair!(int, int))(pair?); But it doesn't work: this call resolves to a general version T getResponse(T), and I get a compilation error because it tries to instantiate readf!(Pair*). What am I doing wrong? On Saturday, 29 November 2014 at 08:06:33 UTC, Ali Çehreli wrote: On 11/28/2014 10:26 PM, Sly wrote: I still don't understand how to read this signature: Point!T getResponse(T: Point!T)(string question) The following is what makes sense to me. Sorry for going step by step but I think it helped me understand your question. (See item 3 below.) 1) Point!T is the return type. Although T is unknown at this point, we will wait a little because it may be a template parameter. Also, according to the syntax of Point!T, Point is apparently a template. So, this function will return the T instantiation of Point, whatever T will be deduced to be in a moment. 2) getResponse is the name of the function 3) The first set of parameters is the template parameters: (T: Point!T) The meaning: T is a type and this specialization is for Point!T. Ok, I think I finally understand your original question. I agree that it doesn't make sense to say T is a type and this specialization is for Point!T. I think we need to read it backward in this case: This specialization is for Point!T. If so, deduce T from that. So, if getResponse is instantiated with Point!int, then T is deduced to be int. 4) The instances of this function template take string parameter. Ali
Re: Can't understand templates
On Saturday, 29 November 2014 at 09:11:51 UTC, Ali Çehreli wrote: Point!T getResponse(P : Point!T, T)(string question) { // ... } This doesn't work because now this definition has 2 parameters P and T. I have to specify both like this: auto pt = getResponse!(Point!int, int)(point); which of course defeats the purpose. Otherwise I have ambiguity error: d.d:73: error: d.getResponse called with argument types (string) matches both: d.d(20): getResponse(T)(string question) and: d.d(31): getResponse(P : Point!T, T)(string question) Same thing with specialization for Pair. Actually what I wrote earlier about C++ is wrong because C++ doesn't allow partial specialization for functions. I wrote this example in C++ using classes: templatetypename T struct Reader { static T getResponse(const std::string question) { std::cout question ( typeid(T).name() ): ; T res; std::cin res; return res; } }; templatetypename T struct Point { T x, y; }; templatetypename T struct ReaderPointT { static PointT getResponse(const std::string question) { std::cout question \n; PointT res; res.x = ReaderT::getResponse( x); res.y = ReaderT::getResponse( y); return res; } }; templatetypename A, typename B struct Readerstd::pairA, B { static std::pairA, B getResponse(const std::string question) { std::cout question \n; std::pairA, B res; res.first = ReaderA::getResponse( first); res.second = ReaderB::getResponse( second); return res; } }; int main() { int i = Readerint::getResponse(int); auto pt = ReaderPointint::getResponse(point); auto pair = Readerstd::pairint, int::getResponse(pair); return 0; } I translated it literally into D using your syntax and it worked! class Reader(T) { public static T getResponse(string question) { writef(%s (%s): , question, T.stringof); T response; readf( %s, response); return response; } } class Reader(P: Point!T, T) { public static Point!T getResponse(string question) { writefln(%s (Point!%s), question, T.stringof); auto x = Reader!T.getResponse( x); auto y = Reader!T.getResponse( y); return Point!T(x, y); } } class Reader(P: Pair!(A, B), A, B) { public static Pair!(A, B) getResponse(string question) { writefln(%s (Pair!(%s, %s)), question, A.stringof, B.stringof); auto a = Reader!A.getResponse( a); auto b = Reader!B.getResponse( b); return new Pair!(A, B)(a, b); } } void main() { auto i = Reader!int.getResponse(int); auto pt = Reader!(Point!int).getResponse(point); auto pair = Reader!(Pair!(int, int)).getResponse(pair); } My questions now are: 1. Apparently D has partial specializations of function templates, but it uses a weird syntax (T: Point!T). How to extend this syntax for multiple template parameters? (Basically, how to write this example without wrapping the function into a class?) 2. Why is there a difference between partial specialization of function templates and class templates: there's a compilation error with function templates but not with class templates?
Re: Can't understand templates
You miss another definition which introduces a conflict: T getResponse(T)(string question) {...} On Saturday, 29 November 2014 at 17:20:42 UTC, Meta wrote: On Saturday, 29 November 2014 at 11:07:34 UTC, Sly wrote: On Saturday, 29 November 2014 at 09:11:51 UTC, Ali Çehreli wrote: Point!T getResponse(P : Point!T, T)(string question) { // ... } This doesn't work because now this definition has 2 parameters P and T. I have to specify both like this: auto pt = getResponse!(Point!int, int)(point); which of course defeats the purpose. Otherwise I have ambiguity error: Not true, T is inferred based on the the type Point has been instantiated with, letting you emit the second template argument. The following code works: struct Point(T) { T x; T y; } P getResponse(P: Point!T, T)(string message) { return P(T.init, T.init); } void main() { import std.stdio; //T is inferred to be int automatically writeln(getResponse!(Point!int)(test)); }
Re: Can't understand templates
This is clearly an incorrect way because it requires editing the original definition every time a new class is introduced. On Saturday, 29 November 2014 at 19:10:34 UTC, Meta wrote: On Saturday, 29 November 2014 at 18:19:40 UTC, Sly wrote: You miss another definition which introduces a conflict: T getResponse(T)(string question) {...} In that case, you're better off with a pair of declarations: struct Point(T) { T x; T y; } T getResponse(T)(string message) if (!is(T == Point!U, U)) { return T.init; } Point!T getResponse(T)(string message) if (is(T == Point!U, U)) { return Point!T(T.init, T.init); } void main() { auto t = getResponse!int(test); auto p = getResponse!(Point!int)(test); }
Re: Can't understand templates
OK. I'm using gdc 4.8.2 and this doesn't compile, so it's probably an old version. Checked on ideone and it works with dmd-2.042. Thanks a lot for your help! On Saturday, 29 November 2014 at 20:16:24 UTC, Ali Çehreli wrote: On 11/29/2014 10:19 AM, Sly wrote: You miss another definition which introduces a conflict: T getResponse(T)(string question) {...} The following works with dmd git head: import std.stdio; T getResponse(T)(string question) { writef(%s (%s): , question, T.stringof); T response; readf( %s, response); return response; } class Pair(A, B) { A a; B b; this(A a, B b) {this.a = a; this.b = b;} } Pair!(A, B) getResponse(P : Pair!(A, B), A, B)(string question) { writeln(question); auto a = getResponse!A( a); auto b = getResponse!B( b); return new Pair!(A, B)(a, b); } struct Point(T) { T x; T y; } Point!T getResponse(P : Point!T, T)(string question) { writefln(%s (Point!%s), question, T.stringof); auto x = getResponse!T( x); auto y = getResponse!T( y); return Point!T(x, y); } void main() { auto number = getResponse!int(number?); writeln(number); auto pair = getResponse!(Pair!(int, long))(pair?); writeln(pair); auto point = getResponse!(Point!int)(point?); writeln(point); } Ali
Can't understand templates
Here is an example from the tutorial: struct Point(T) { T x; T y; } T getResponse(T)(string question) { writef(%s (%s): , question, T.stringof); T response; readf( %s, response); return response; } Point!T getResponse(T: Point!T)(string question) { writefln(%s (Point!%s), question, T.stringof); auto x = getResponse!T( x); auto y = getResponse!T( y); return Point!T(x, y); } void main() { auto pt = getResponse!(Point!int)(point); } I don't understand how to read this signature: Point!T getResponse(T: Point!T)(string question). Clearly it's not supposed to be saying that T is subclass of Point!T, so those Ts must refer to different types. But when I rename it to getResponse(U: Point!T) I get a compilation error (unknown identifier T). Another question: say I have a template class Pair: class Pair(A, B) { A a; B b; this(A a, B b) {this.a = a; this.b = b;} } How to write a specialization for getResponse matching Pair!(A, B) with any type arguments A and B? I tried this: T getResponse(T)(string question) if (is(T: Pair!(A, B), A, B)) { auto a = getResponse!A( a); auto b = getResponse!B( b); return new Pair!(A, B)(a, b); } but get a compile error: error: d.getResponse called with argument types (string) matches both: d.d(19): getResponse(T)(string question) and: d.d(40): getResponse(T)(string question) if (is(T : Pair!(A, B), A, B))
Re: Can't understand templates
On Friday, 28 November 2014 at 19:45:48 UTC, H. S. Teoh via Digitalmars-d-learn wrote: This syntax is a little confusing, but basically the : there is saying this type, when instantiated with the following pattern, produces a valid type. Essentially it's equivalent to: Point!T getResponse(T)(string question) if (is(typeof(Point!T))) // i.e., Point!T is a valid type { ... } Is there a typo here? This version doesn't compile with the original call: auto pt = getResponse!(Point!int)(point); Yes, because D does not support overlapping template overloads. But I thought the original example has ovelapping templates. Let's take a simpler example from earlier in the tutorial, where Point is a non-template struct: // The general definition of the function template (same as before) T getResponse(T)(string question) { writef(%s (%s): , question, T.stringof); T response; readf( %s, response); return response; } // The specialization of the function template for Point T getResponse(T : Point)(string question) { writefln(%s (Point), question); auto x = getResponse!int( x); auto y = getResponse!int( y); return Point(x, y); } auto center = getResponse!Point(Where is the center?); Doesn't getResponse!Point match both declarations?
Re: Can't understand templates
OK, so we *can* have overlapping templates in one fits better than another, just like in C++. I still don't understand how to read this signature: Point!T getResponse(T: Point!T)(string question) On Friday, 28 November 2014 at 23:59:07 UTC, Ali Çehreli wrote: On 11/28/2014 12:36 PM, Sly wrote: Let's take a simpler example from earlier in the tutorial, where Point is a non-template struct: // The general definition of the function template (same as before) T getResponse(T)(string question) { [...] } That definition would work with any type T. So, it is general: it accepts any type. // The specialization of the function template for Point T getResponse(T : Point)(string question) { [...] } That definition is for T that matches Point (i.e. Point itself in this example). So, it is special: it accepts only that type. auto center = getResponse!Point(Where is the center?); Doesn't getResponse!Point match both declarations? True but the call is dispatched to the most special of all of the matches. It is very briefly explained through a reference to C++: The template picked to instantiate is the one that is most specialized that fits the types of the TemplateArgumentList. Determine which is more specialized is done the same way as the C++ partial ordering rules. If the result is ambiguous, it is an error. See the Specialization heading here: http://dlang.org/template.html Ali