Getting around the non-virtuality of templates

Steven Schveighoffer schveiguy at yahoo.com
Mon Mar 26 06:37:22 PDT 2012


On Sun, 25 Mar 2012 18:36:08 -0400, Stewart Gordon <smjg_1998 at yahoo.com>  
wrote:

> I'm coming up against some interesting challenges while porting stuff in  
> my utility library to D2.
>
> Firstly, D2 uses opBinary and opOpAssign, rather than the  
> operator-specific op* and op*Assign.  While the latter still work, they  
> aren't mentioned in the current D2 docs. Which would imply that they're  
> on the way out; however, there's no mention at
> https://github.com/D-Programming-Language/d-programming-language.org/blob/master/deprecate.dd
>
> (See also
> http://d.puremagic.com/issues/show_bug.cgi?id=7779 )
>
> Still, it seems clear that opBinary/opOpAssign is the D2 way of doing  
> it.  But it has the drawback that, because it's a template, it isn't  
> virtual.  One way about it is to keep the D1-style op functions and make  
> opUnary/opBinary/opOpAssign call these.  But is there a better way?

I have definitely had issues with this.  In dcollections, I have versions  
of opBinary commented out, because at the time of writing, templates  
weren't allowed in the D compiler.  I filed this bug:  
http://d.puremagic.com/issues/show_bug.cgi?id=4174  Looks like it hasn't  
been closed yet...

So for now, I use the undocumented old-style functions.  One other thing  
that this "wrapper" method loses is covariance, which I use a lot in  
dcollections.  I haven't filed a bug on it, but there is at least a  
workaround on this one -- the template can capture the type of "this" from  
the call site as a template parameter.

> The other isn't a D2-specific issue, though D2 increases the  
> significance of it.  I have a method with the signature
>
>      Set opAnd(bool delegate(Element) dg)
>
> I would like to enable a user of the library to pass in a delegate whose  
> parameter is any type to which Element is implicitly convertible.  This  
> could be the same type as Element with the top-level constancy changed  
> (probably the main use case), or a type that is distinct beyond the  
> constancy level.  Turning it into a template
>
>      Set opAnd(E)(bool delegate(E) dg)
>
> would address this, but prevent overriding with the appropriate code for  
> each set implementation.

What I would do is this (assuming template interfaces worked):

Set opAnd(E)(bool delegate(E) dg) if(is(E == Element))
{
    // call protected virtual opAnd equivalent which takes delegate of  
Element
}

Set opAnd(E)(bool delegate(E) dg) if(!is(E == Element) &&  
implicitlyConvertsTo!(E, Element))
{
    bool _dg(Element e)
    {
       return dg(e);
    }
    // call protected virtual opAnd equivalent with &_dg
}

Note, with proper delegate implicit conversions, you could probably get  
some better optimization (including delegates that only differ by const)  
by checking if the delegate implicitly converts instead of the element.

-Steve


More information about the Digitalmars-d mailing list