<br><br><div class="gmail_quote">On Thu, Dec 27, 2012 at 9:01 PM, comco <span dir="ltr"><<a href="mailto:void.unsigned@gmail.com" target="_blank">void.unsigned@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
I wrote a simple template mixin to hold common operator overloads:<br>
<br>
mixin template VectorSpaceOpsMixin(Vector, Scalar, alias a, alias b)<br>
{<br>
    Vector opUnary(string op)() if (op == "-") {<br>
        return Vector(-a, -b);<br>
    }<br>
    ...<br>
}<br>
<br>
This works like this:<br>
<br>
struct complex {<br>
    double a, b;<br>
    mixin VectorSpaceOpsMixin!(complex, double, a, b);<br>
    ...<br>
}<br>
<br>
Now this is nice, but it only works when the vector has 2 parts. Can the mixin template be made more general? What will then be its definition? This don't work:<br>
mixin template `VectorSpaceOpsMixin(Vector, Scalar, alias... parts) { ... }`<br></blockquote><div><br></div><div><br></div><div>First, the `Vector` part is redundant. You can use `typeof(this)` inside your mixin to have it 'look around` when it's being mixed in and determine the type of the local `this`. </div>
<div><br></div><div>So you mixin can become:</div><div><br></div><div>    mixin VectorSpaceOpsMixin!(double, a, b);</div><div><br></div><div>The `double` part could be deduced also, but it depends what kind of layout you envision for your host structs. I'll let it there.</div>
<div><br></div><div>Now, concerning your question, you can make `parts` a template tuple parameter:</div><div><br></div><div>    VectorSpaceOpsMixin(Vector, Scalar, args...) {</div><div><br></div><div><br></div><div>The trouble is then that </div>
<div><br></div><div>    mixin VectorSpaceOpsMixin!(complex, double, a, b);</div><div><br></div><div>will have `args` be the tuple (a,b) (it contains the symbols, not directly the value themselves). Tuples are not arithmetic values in D (that would not make sense for most tuples), so you cannot do `-args` directly.</div>
<div><br></div><div>From there, it depends whether you really want the flexibility that passing a and b around gives you, or if you can make some simplifying assumptions concerning your host struct.</div><div><br></div><div>
Solution #1: full flexibility: you want to keep the capability to name the fields upon which the mixin will act.</div><div><br></div><div>That way, even with </div><div><br></div><div>    struct Vector { double a,b,c; } </div>
<div><br></div><div>you can have </div><div><br></div><div>    mixin VectorSpaceOpsMixin!(Scalar, a,b); // Look Ma, no c!</div><div><br></div><div><br></div><div>You can iterate on `args`. By using `.stringof` on its elements, you get "this.a", "this.b", ... From that, you can create the wanted code. Here is a possibility:</div>
<div><br></div><div><div>mixin template VectorSpaceOpsMixin(Scalar, args...)</div><div>{</div><div>    typeof(this) opUnary(string op)() if (op == "-") {</div><div>        typeof(this) temp;</div><div>        // "temp.a = -this.a;"...</div>
<div>        foreach(index, arg; args)</div><div>            mixin("temp" ~ args[index].stringof[4..$] ~ " = -" ~ args[index].stringof ~ ";");</div><div><br></div><div>        return temp;</div>
<div>    }</div><div>}</div></div><div><br></div><div>It creates a temporary, but then a direct return solution would also have to make one. The only thing I'm not sure is when using floating point types: `temp.a` and `temp.b` are all initialized with NaN. I don't know if it's slow to assign another floating point to a NaN. I guess a one line solution is doable, with a bit of string mixin magic.</div>
<div><br></div><div><br></div><div>Btw, of course, there will be many duplication between the different arithmetic operators. You can also write another template to, er, write your mixin for you. But I personally wouldn't bother: it's easier to maintain explicit code.</div>
<div> </div><div><br></div><div>Solution # 2: the mixin will act on all fields inside the struct => no need to pass the names around. In this case, I would even use the first field as the type of Scalar. </div><div><br>
</div><div>Everything is greatly simplified:</div><div><br></div><div><div>mixin template VectorSpaceOpsMixin2() // no args!</div><div>{</div><div>    typeof(this) opUnary(string op)() if (op == "-") {</div><div>
        typeof(this) temp;</div><div><br></div><div>        foreach(index, ref arg; temp.tupleof)</div><div>            arg = -this.tupleof[index];</div><div><br></div><div>        return temp;</div><div>    }</div><div>}</div>
<div><br></div><div>struct Complex {</div><div>    double a, b;</div><div>    mixin VectorSpaceOpsMixin2;</div><div>}</div></div><div><br></div><div>Don't worry about the foreach: it's all unrolled at compile-time.</div>
<div><br></div><div><br></div><div><br></div></div>