On Thu, 11 Mar 2010 19:15:37 -0500, Trass3r <[email protected]> wrote:
I stumbled across this while playing with operator overloading. Since
they are now function templates, this becomes an issue.
struct Vector2(T)
{
T x;
T y;
/// element-wise operations, +, -,
Vector2 opBinary(string op)(ref Vector2 v)
{
mixin("return Vector2!(T)( cast(T)(x " ~ op ~ " v.x), cast(T)(y " ~ op
~ " v.y) );");
}
/// operation with scalar
Vector2 opBinary(string op)(int i)
{
mixin("return Vector2!(T) ( cast(T)(x " ~ op ~ " i), cast(T)(y " ~ op
~ " i) );");
}
}
This yields:
template instance opBinary!("+") matches more than one template
declaration
Of course this can be circumvented by using
opBinary(string op, U:Vector2)(U v)
opBinary(string op, U:int)(U v)
But is this how it's supposed to be done? Couldn't the compiler detect
that itself?
The issue is with two things.
First, there are two instantiations of the template. You have to realize
that a template is somewhat of a namespace, and they do not append to
eachother. Think about it this way, a template function is really a
shortcut for this:
template fn(T)
{
fn(args) {...}
}
So what you have done is:
template fn(T)
{
fn(args1) {...}
}
template fn(T)
{
fn(args2) {...}
}
The compiler doesn't combine the two templates together, so it doesn't
know which namespace you are talking about.
I tried something like this:
template fn(T)
{
fn(args1) {...}
fn(args2) {...}
}
but this doesn't work, because the compiler refuses to call the function
via fn!(T)(args1).
I think the only option you are faced with at the moment is to include the
argument type in the template specification, thereby separating the
namespace.
You should file a bug on this. I think it's not a good result of the new
operator overloading regime. However, I think it can be fixed, by either
handling template function overloads, or having the compiler rewrite
x + b
as
x.opBinary!("+").opBinary(b);
since we aren't even using IFTI here. Then my proposed overloaded
template functions will work.
-Steve