www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Instantiating a class with range template parameter

reply Jon Degenhardt <jond noreply.com> writes:
I've been generalizing output routines by passing an OutputRange 
as an argument. This gets interesting when the output routine is 
an virtual function. Virtual functions cannot be templates, so 
instead the template parameters need to be part of class 
definition and specified when instantiating the class.

An example is below. It works fine. One thing I can't figure out: 
how to provide the range parameter without first declaring a 
variable of the appropriate type. What works is something like:

     auto writer = stdout.lockingTextWriter;
     auto x = new Derived!(typeof(writer));

Other forms I've tried fail to compile. For example, this fails:

     auto x = new Derived!(typeof(stdout.lockingTextWriter));

I'm curious if this can be done without declaring the variable 
first. Anyone happen to know?

--Jon

Full example:

import std.stdio;
import std.range;

class Base(OutputRange)
{
     abstract void writeString(OutputRange r, string s);
}

class Derived(OutputRange) : Base!OutputRange
{
     override void writeString(OutputRange r, string s)
     {
         put(r, s);
         put(r, '\n');
     }
}

void main()
{
     auto writer = stdout.lockingTextWriter;
     auto x = new Derived!(typeof(writer));
     x.writeString(writer, "Hello World");
}
Sep 08 2016
parent reply Lodovico Giaretta <lodovico giaretart.net> writes:
On Thursday, 8 September 2016 at 08:20:49 UTC, Jon Degenhardt 
wrote:
 I've been generalizing output routines by passing an 
 OutputRange as an argument. This gets interesting when the 
 output routine is an virtual function. Virtual functions cannot 
 be templates, so instead the template parameters need to be 
 part of class definition and specified when instantiating the 
 class.

 An example is below. It works fine. One thing I can't figure 
 out: how to provide the range parameter without first declaring 
 a variable of the appropriate type. What works is something 
 like:

     auto writer = stdout.lockingTextWriter;
     auto x = new Derived!(typeof(writer));

 Other forms I've tried fail to compile. For example, this fails:

     auto x = new Derived!(typeof(stdout.lockingTextWriter));

 I'm curious if this can be done without declaring the variable 
 first. Anyone happen to know?

 --Jon

 Full example:

 import std.stdio;
 import std.range;

 class Base(OutputRange)
 {
     abstract void writeString(OutputRange r, string s);
 }

 class Derived(OutputRange) : Base!OutputRange
 {
     override void writeString(OutputRange r, string s)
     {
         put(r, s);
         put(r, '\n');
     }
 }

 void main()
 {
     auto writer = stdout.lockingTextWriter;
     auto x = new Derived!(typeof(writer));
     x.writeString(writer, "Hello World");
 }
I think that auto x = new Derived!(typeof(stdout.lockingTextWriter()))(); // note the parenthesis should work. But usually, you save the writer inside the object and make a free function called `derived` (same as the class, but with lowercase first). You define it this way: auto derived(OutputRange)(auto ref OutputRange writer) { auto result = new Derived!OutputRange(); result.writer = writer; // save the writer in a field of the object return result; } void main() { auto x = derived(stdout.lockingTextWriter); x.writeString("Hello world"); // the writer is saved in the object, no need to pass it }
Sep 08 2016
parent Jon Degenhardt <jond noreply.com> writes:
On Thursday, 8 September 2016 at 08:44:54 UTC, Lodovico Giaretta 
wrote:
 On Thursday, 8 September 2016 at 08:20:49 UTC, Jon Degenhardt 
 wrote:
 [snip]
 
I think that auto x = new Derived!(typeof(stdout.lockingTextWriter()))(); // note the parenthesis should work. But usually, you save the writer inside the object and make a free function called `derived` (same as the class, but with lowercase first). You define it this way: auto derived(OutputRange)(auto ref OutputRange writer) { auto result = new Derived!OutputRange(); result.writer = writer; // save the writer in a field of the object return result; } void main() { auto x = derived(stdout.lockingTextWriter); x.writeString("Hello world"); // the writer is saved in the object, no need to pass it }
Yes, the form you suggested works, thanks! And thanks for the class structuring suggestion, it has some nice properties.
Sep 08 2016