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



Reply via email to