On Wed, 25 Aug 2010 16:54:19 -0400, Andrej Mitrovic
<[email protected]> 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