How to require operator overloading in interface

JS js.mdnq at gmail.com
Sat Jul 20 09:46:51 PDT 2013


On Saturday, 20 July 2013 at 13:27:03 UTC, H. S. Teoh wrote:
> On Sat, Jul 20, 2013 at 12:13:49PM +0200, JS wrote:
>> On Saturday, 20 July 2013 at 01:37:13 UTC, Jesse Phillips 
>> wrote:
>> >The relevant blog post:
>> >
>> >http://3d.benjamin-thaut.de/?p=94
>> >
>> >What you should understand is template functions are not/can 
>> >not
>> >be virtual. They do not exist until they are instantiated. 
>> >Thus
>> >you can not require that they be overloaded.
>> 
>> And this is a compiler limitation? After all, templated 
>> functions
>> are ultimately just normal functions...
>
> Nope. Templated functions don't exist until they're 
> instantiated. Which
> means the compiler can't know in advance how many 
> instantiations there
> will be and which ones they are. And given that D supports 
> separate
> compilation, you *can't* know this (even after linking, there's 
> the
> possibility that some external dynamic library might 
> instantiate yet
> another version of the function).
>
> There are ways of implementing overloadable templated 
> functions, of
> course. But they are rather complicated to implement, and incur 
> runtime
> overhead.
>
>
>> In my case the template parameter is explicitly known and the
>> overloadable operations being templated isn't my fault.
>> 
>> I guess I can redirect each templated function to a 
>> non-templated
>> version using the method in benjamin's page but this seems 
>> like it
>> defeats exactly what templates are for...
>
> Not really. Having operator overloading implemented as template
> functions give you more flexibility (albeit at the cost of more 
> code
> complexity). You could either redirect each operator to an 
> overridable
> function, or you could do this:
>
> 	class MyClass {
> 		auto opBinary(string op)(T t) {
> 			// Buahaha, now op is a runtime parameter
> 			return opBinaryImpl(op, t);
> 		}
> 		auto opBinaryImpl(string op, T t) {
> 			// which means this method is overridable in
> 			// derived classes.
> 			...
> 		}
> 	}
>
> You could also do this only for a certain subset of operators, 
> depending
> on what granularity you wish to have.
>
> I'd write more, but I gotta run. Maybe later.
>
>
> T

Thanks. I still think that interfaces define contracts that must 
be followed. If define an interfaces to use an operator I think 
any inheritance of it must implement that operator.

This might not work for templated members but should work for 
them if they are specialized.

e.g., we might not be able to do opOpAssign(string)() but we 
should be able to use opOpAssign(string op : "+")() to enforce a 
contract... in this case it not really any different than the 
code you show excep it is more natural(instead of opBinaryImpl we 
actually get to use opOpAssign as the name).

e.g.,


  	class MyClass {
  		auto opBinary(string op : "|" T : int)(T t) { }
                 // opBinary is completely specialized and is no 
different than a regular function, it can be overridden directly 
in children without having to use a redirection. (note in your 
opBinaryImpl, T must be specified
  	}

This way any children of MyClass *can* override the operation if 
necessary and inheritance actually works for templates to some 
degree. In fact, it should almost alway work because type 
parameter information can be used to pass to a normal function.

auto opBinary(string op, T)(T t)
{
     returnopBinaryImpl(op, typeinfo(T), cast(object)t);
}

auto opBinaryImpl(string op, typeinfo type, object value) { }

so we could use this for the general case but then have the 
specifications for the cases we know about at the time of 
design.... but users of the base class can design their own 
operators to use(at a performance cost).





More information about the Digitalmars-d-learn mailing list