More TDPL overloads

Steven Schveighoffer schveiguy at yahoo.com
Wed Aug 25 14:24:00 PDT 2010


On Wed, 25 Aug 2010 16:54:19 -0400, Andrej Mitrovic  
<andrej.mitrovich at name.com> wrote:

> Page 373 adds another operator overload for use with integral numbers  
> (CheckedInt op Int). But it conflicts with the previos template  
> (CheckedInt op CheckedInt):
>
> module binary_ops;
>
> import std.stdio : writeln;
> import std.traits;
> import std.exception;
>
> unittest
> {
>     auto foo = CheckedInt!(int)(5);
>
>     foo + 4;
> }
>
> void main()
> {
> }
> struct CheckedInt(N) if (isIntegral!N)
> {
>     private N value;
>     public int x;
>    this(N value)
>     {
>         this.value = value;
>     }
>    // Operation with raw numbers
>     CheckedInt opBinary(string op)(N rhs) if (isIntegral!N)
>     {
>         return opBinary!op(CheckedInt(rhs));
>     }
>    // addition
>     CheckedInt opBinary(string op)(CheckedInt rhs) if (op == "+")
>     {
>         auto result = value + rhs.value;
>        enforce(rhs.value >= 0 ? result >= value : result < value);
>         return CheckedInt(result);
>     }
> }
>
> I get back:
>
> binary_ops.d(34): Error: template instance opBinary!(op) matches more  
> than one template declaration,
> binary_ops.d(32):opBinary(string op) if (isIntegral!(N)) and
> binary_ops.d(38):opBinary(string op) if (op == "+")
>
> One is taking an integral by using a constraint, the other specifically  
> a CheckedInt type. Any clues how they both match?
>
> If I remove the first operator overload template then I can't compile,  
> so where's the ambiguity?

This is an issue with template overloading.

To the compiler, the template instantiations are identical, because  
opBinary(string op) only has one template parameter.  The arguments to the  
function are only looked at afterwards for overloading.  So the compiler  
wants to make a decision first of which *template* to instantiate, the  
first or the second, then looks at function overloading.

I believe there's a bug on this in bugzilla already.  It makes things more  
difficult for operator overloading.

Also that first function signature is wrong.  N is not a template  
parameter to the *function* and isIntegral!N is already checked on the  
struct, so there is no need to add that constraint again.  So with the  
constraint removed, we can work around the problem by adding a superfluous  
template argument

>    // Operation with raw numbers
>     CheckedInt opBinary(string op, T)(T rhs) if (is(T == N))
>     {
>         return opBinary!op(CheckedInt(rhs));
>     }
>    // addition
>     CheckedInt opBinary(string op, T)(T rhs) if (op == "+" && is(T ==  
> CheckedInt))
>     {
>         auto result = value + rhs.value;
>        enforce(rhs.value >= 0 ? result >= value : result < value);
>         return CheckedInt(result);
>     }

-Steve


More information about the Digitalmars-d-learn mailing list