February 01, 2014
So this is the general form of what I'm trying to do:


import std.stdio;

class Foo(uint something)
{
  Foo opBinary(string op)(Foo rhs) const
    if (op == "*")
  {
    writeln("calling Foo.*");
  }
}

class Bar : Foo!(3)
{
  // ...
}

class Baz : Foo!(4)
{
  //...
}

void main()
{
  auto bar = new Bar();
  auto baz = new Baz();

  auto foo = bar * baz;
  // errors with
  // tinker.d(28): Error: 'cast(Object)bar' is not of arithmetic type, it is a object.Object
  // tinker.d(28): Error: 'baz' is not of arithmetic type, it is a tinker.Baz
}


I'm still fairly new to D, and my google-fu has failed me. I don't understand this error. If I remove the templating from all 3 classes, it compiles just fine, and does what I would expect.

It feels like the compiler is maybe ignoring Foo.opBinary? Does the compiler not consider Foo!4 to be a valid argument for Foo.opBinary? If that's the case, is there a way to tell the compiler that Foo.opBinary should accept all specializations for a parameter?
February 01, 2014
Matthew Dudley:

> I'm still fairly new to D, and my google-fu has failed me. I don't understand this error.

You have to remember that an instantiated template creates a totally distinct type.

There are few different ways to face your problem, this is one of them:


import std.stdio;

class Foo(uint N) {
    Foo opBinary(string op, uint N2)(Foo!N2 rhs) const
    if (op == "*") {
        "calling Foo.*".writeln;
        return new Foo;
    }
}

class Bar: Foo!3 {}
class Baz: Foo!4 {}

void main() {
    auto bar = new Bar;
    auto baz = new Baz;
    auto foo = bar * baz;
}


Bye,
bearophile