Any trick for defining an operator overload in a different namespace?

Artur Skawina art.08.09 at gmail.com
Sat Aug 31 06:26:26 PDT 2013


On 08/31/13 12:07, Andrej Mitrovic wrote:
> But this explicitly stores the 'this' reference in the struct, I was
> wondering if anyone knows of a trick to avoid having to do that. As
> you can tell I just want a more convenient operator-based syntax over
> calling the 'assign' method, but I don't want the operator to live in
> the class space itself (because then I'd have to use "this[...] =
> that", which is a little quirky for my taste).

Not sure this qualifies as a "trick", but it does what you're asking
for and can be extended further.

   struct A {
      mixin Namespace!("x", "x_");
      int x_min = 42;
      int x_max(int a) { return a/2; }
      int x_sum(int a, int b) { return a+b; }
      @property int x_prop() { return 23; }
      @property int x_prop(int a) { return a*a; }
      @property int setmin(int a) { return x_min = a; }

      mixin Namespace!("opts", "opts_");
      void opts_opIndexAssign(T)(T value, string option) {
         if (option=="min")
            x_min = value;
      }
   }

   class C {
      mixin Namespace!("x", "x_");
      int x_min = 42;
      int x_max(int a) { return a/2; }
      int x_sum(int a, int b) { return a+b; }
      @property int x_prop() { return 23; }
      @property int x_prop(int a) { return a*a; }

      mixin Namespace!("opts", "opts_");
      void opts_opIndexAssign(T)(T value, string option) {
         if (option=="min")
            x_min = value;
      }
   }

   import std.stdio;
   int main() {
      A a;
      //C a = new C;  // Works too.
      writeln(a.x.min);
      a.x.min = 17;
      writeln(a.x.min);
      writeln(a.x.max(4));
      writeln(a.x.sum(4, 3));
      writeln(a.x.prop);
      writeln(a.x.prop=42);
      a.x.min = 13;
      writeln(a.x.min);

      a.opts["min"] = 1234;
      writeln(a.x.min);

      const A ca;
      writeln(ca.x.min);
      writeln(typeof({return ca.x.min;}()).stringof);
      // ca.x.min = 13; // Disallowed.

      return 0;
   }

   struct NS(O, string PF) {
      O _realobjref;
      template opDispatch(string M) {
         enum _EVALSTR = "this.tupleof[0]."~PF~M;
         @property auto ref opDispatch()()
          if (is(typeof(function { auto _ = mixin(_EVALSTR); }))) {
            return mixin(_EVALSTR);
         }
         @property auto ref opDispatch(A)(A a)
          if (is(typeof(function { return mixin(_EVALSTR~"=a"); }))) {
            return mixin(_EVALSTR~"=a");
         }
         auto ref opDispatch(A...)(A a)
          if (is(typeof(function { return mixin(_EVALSTR~"(a)"); }))) {
            return mixin(_EVALSTR~"(a)");
         }
      }

      auto ref opIndexAssign(A...)(auto ref A a) { // XXX Won't work if there are ref&non-ref overloads.
         return mixin("this.tupleof[0]."~PF~"opIndexAssign(a)");
      }
   }

   mixin template Namespace(string N, string P) {
      mixin(q{
      template }~N~q{(this THIS) }~"{"~q{
         @property }~N~q{() const @trusted }~"{"~q{
                 static if (is(THIS==struct)) return NS!(THIS*, }~P.stringof~q{)(cast(THIS*)&this);
            else static if (is(THIS==class))  return NS!(THIS, }~P.stringof~q{)(cast(THIS)this);
            else static assert (0);
         }~"}\n"~
      "}"
      );
   }


artur


More information about the Digitalmars-d-learn mailing list