Search code examples
templatesconstructormetaprogrammingd

How to call a constructor from a mixedin mixin template


If I do something like

mixin template T() {
  float y;
  this(float y_){
    y = y_;
  }
}
class C {
  mixin T!() t;
  int x;
  this(int x_, float y_){
    x = x_;
    this(y_);
  }
}
//
C c = new C(5, 7.0f);

This gives the error constructor C.this (int x_, float y_) is not callable using argument types (float). On the line that contains this(y_); in C's constructor, which seems to imply that C can't see the constructor imported from T. Though, it should.

Obviously t.this(...) and T!().this(...) don't work.

The most obvious workaround I can think of is like (a proxy):

template T(...) {
  void constructor(...){...}
  this(Args...)(Args args){ constructor(args); }
}
...
class C {
   mixin T!() t;
   this(...){
     t.constructor(...);
   }
}

But that sucks because it puts more knowledge overhead on T (using the constructor requires doing something special)

Is there any way to call t's constructor in a non-weird (and non-special-case) way? Also, is this a bug? If not, why does it work this way?


Solution

  • The issue stems from the fact that things mixed into an aggregate via mixin templates are not inserted into the aggregate's overload set.

    For normal methods the way to get around that is to use an alias into the scope introduced by the template mixin like so:

    mixin template T()
    {
        void foo()
        {
        }
    }
    
    class C
    {
        mixin T!() t;
        alias foo = t.foo;
    
        void foo(int _)
        {
            foo();
        }
    }
    

    However, for constructors, the analogue doesn't work and it's a reported bug:

        alias this = t.this;    // Won't compile
        alias __ctor = t.__ctor // Using the hidden __ctor name won't compile, either
    

    If you don't need to call the mixed in constructor from outside, you can call it via the builtin name:

    mixin template T()
    {
        float y;
        this(float y_)
        {
            y = y_;
        }
    }
    class C
    {
        mixin T!() t;
        int x;
        this(int x_, float y_)
        {
            x = x_;
            t.__ctor(y_); // This
        }
    }