digitalmars.D.learn - how to properly overload function templates?
- Trass3r (26/26) Mar 11 2010 I stumbled across this while playing with operator overloading. Since th...
- bearophile (16/22) Mar 11 2010 The compiler can probably do that by itself, but to do that I think temp...
- Steven Schveighoffer (41/68) Mar 12 2010 The issue is with two things.
- bearophile (5/6) Mar 12 2010 That's the more general solution. Do you know how much hard is to implem...
- Steven Schveighoffer (10/16) Mar 12 2010 I imagine it's not trivial. You would be combining multiple templates
- Don (3/12) Mar 15 2010 Walter tried to do it, about a year ago, but gave up because it turned
- bearophile (4/6) Mar 15 2010 I think the refused C++0x feature of "Extern template" has some semantic...
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?
Mar 11 2010
Trass3r: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 compiler can probably do that by itself, but to do that I think templates need to change a little how they work. That code doesn't look too much bad, I think it's acceptable. You can also use template constraints, but the code gets a little worse: opBinary(string op, T)(T v) if (is(T == Vector2) { opBinary(string op, T)(T v) if (is(T == int) { Or you can squash it in a single template, but I think it's worse: opBinary(string op, T)(T v) { static if (is(T == Vector2) { ... } else static if (is(T == int) { ... } else assert(0, "..."); } Bye, bearophile
Mar 11 2010
On Thu, 11 Mar 2010 19:15:37 -0500, Trass3r <un known.com> 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
Mar 12 2010
Steven Schveighoffer:However, I think it can be fixed, by either handling template function overloads,That's the more general solution. Do you know how much hard is to implement that? Do you see any downsides or possible bad side effects? Bye, bearophile
Mar 12 2010
On Fri, 12 Mar 2010 08:52:29 -0500, bearophile <bearophileHUGS lycos.com> wrote:Steven Schveighoffer:I imagine it's not trivial. You would be combining multiple templates into one. At the very least, it should be restricted to a single module. I would restrict it also to templates that have only eponymous members (members of the same name). You would also have to allow a template with multiple eponymous functions to resolve to the overload set of those functions. The compiler currently does not allow that (or my workaround would have compiled). -SteveHowever, I think it can be fixed, by either handling template function overloads,That's the more general solution. Do you know how much hard is to implement that? Do you see any downsides or possible bad side effects?
Mar 12 2010
bearophile wrote:Steven Schveighoffer:Walter tried to do it, about a year ago, but gave up because it turned out to be too difficult.However, I think it can be fixed, by either handling template function overloads,That's the more general solution. Do you know how much hard is to implement that? Do you see any downsides or possible bad side effects? Bye, bearophile
Mar 15 2010
Don:Walter tried to do it, about a year ago, but gave up because it turned out to be too difficult.I think the refused C++0x feature of "Extern template" has some semantic relation to this, and it too much hard to implement. Better to not make the compiler overly-complex. Bye, bearophile
Mar 15 2010