digitalmars.D.learn - Templates for instantiating derived class
- rjkilpatrick (40/40) Sep 20 2021 Essentially, I would like to write a template that calls the
- Adam Ruppe (25/31) Sep 20 2021 Make this
- Steven Schveighoffer (38/46) Sep 20 2021 What you want is to change that operator into a virtual function. Yes,
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 /+ 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.
Sep 20 2021
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.
Sep 20 2021
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); } ```
Sep 20 2021