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).