Re: Templates for instantiating derived class

2021-09-20 Thread Steven Schveighoffer via Digitalmars-d-learn

On 9/20/21 6:16 PM, rjkilpatrick wrote:
Essentially, I would like to write a template that calls the constructor 
of the parent class or the constructor of the inherited class, depending 
on its type.




...


Some kind of `return new this(...)` would be good, but that's not possible.
I think it has to be done with templates, but I'm not sure how to do this.

Any help would be greatly appreciated.


What you want is to change that operator into a virtual function. Yes, 
you still have to write the overrides, but you could if you want use a 
mixin. Adam's solution works, but only uses the static type.


```d
class Super {
private int _a;
this(){}
this(int a) {
_a = a;
}

Super performAdd(int rhs) const {
return new Super(_a + rhs);
}

alias opBinary(string op : "+") = performAdd;
}

class Derived : Super {
this(){}
this(int a) {
_a = a + 1;
}

override Derived performAdd(int rhs) {
return new Derived(_a + rhs);
}
}

void main() {
import std : writeln;

Super foo = new Super(1);
Super foo2 = foo + 1; // Works fine as calls `Super` constructor

Derived bar = new Derived(2);
Derived bar2 = bar + 1; // works now

Super b2 = bar;
Derived d2 = cast(Derived)(b2 + 1); // ok, *and* calls Derive's 
version of performAdd

assert(d2 !is null && d2._a == bar2._a);
}
```


Re: Templates for instantiating derived class

2021-09-20 Thread Adam Ruppe via Digitalmars-d-learn

On Monday, 20 September 2021 at 22:16:47 UTC, rjkilpatrick wrote:

auto opBinary(string op)(int rhs) const if (op == "+") {
return new Super(_a + rhs); // Creates of type Super 
even when called from derived class

}


Make this

auto opBinary(string op, this This)(int rhs) .
  return new This(_a + rhs);
}


The template this param is the static type it is called on.

https://dlang.org/spec/template.html#template_this_parameter


Note though that this is the static type. If you  do

Super thing = new Derived();
thing + 5;


it will still return Super since that's the type it was called 
through. If you want it to actually return derived, you'll have 
to add a virtual factory function:



class Super {
protected Super factory() { return new Super(); }
}

class Derived : Super {
override Derived factory() { return new Derived(); }
}


Then you can call obj.factory to get the right dynamic type. 
(forward args as needed etc.)


Some kind of `return new this(...)` would be good, but that's 
not possible.


You can do `return new typeof(this)(...);` fyi but it is again 
the static type of this, which will be whatever it is where it is 
defined. This is a useful trick if you were to make that factory 
function a mixin template or something though.


Templates for instantiating derived class

2021-09-20 Thread rjkilpatrick via Digitalmars-d-learn
Essentially, I would like to write a template that calls the 
constructor of the parent class or the constructor of the 
inherited class, depending on its type.


```d
#!/usr/bin/env dub
/+ dub.sdl:
name "mwe"
+/
class Super {
private int _a;
this(){}
this(int a) {
_a = a;
}

auto opBinary(string op)(int rhs) const if (op == "+") {
return new Super(_a + rhs); // Creates of type Super even 
when called from derived class

}
}

class Derived : Super {
this(){}
this(int a) {
_a = a + 1;
}
}

void main() {
import std : writeln;

Super foo = new Super(1);
Super foo2 = foo + 1; // Works fine as calls `Super` 
constructor


Derived bar = new Derived(2);
Derived bar2 = bar + 1; // Cannot implicitly cast `Super` to 
`Derived`

}
```

Some kind of `return new this(...)` would be good, but that's not 
possible.
I think it has to be done with templates, but I'm not sure how to 
do this.


Any help would be greatly appreciated.