┌─[alexrp@zor] - [~/Projects/tests] - [2012-08-08 01:52:24]
└─[$] <> cat test.d
import std.stdio;
interface I
{
int* opBinaryRight(string op : "in")(int i);
}
class C : I
{
int* opBinaryRight(string op : "in")(int i)
{
return null;
}
}
void main()
{
I i = new C;
int* p = 42 in i;
writeln(p);
}
┌─[alexrp@zor] - [~/Projects/tests] - [2012-08-08 01:52:26]
└─[$] <> dmd test.d
test.o:test.d:function _Dmain: error: undefined reference to '_D4test1I30__T13opBinaryRightVAyaa2_696eZ13opBinaryRightMFiZPi'
collect2: ld returned 1 exit status
--- errorlevel 1
It's my understanding that this is supposed to work since the opBinaryRight template is constrained specifically to "in". This bug makes operators in interfaces pretty unusable.
Comment #1 by simen.kjaras — 2012-08-07T18:26:30Z
Your understanding is wrong - templates never go in the vtable.
The solution is to use NVI and forwarding:
interface I
{
int* opBinaryRight_in(int i);
int* opBinaryRight(string op : "in")(int i)
{
return opBinaryRight_in(i);
}
}
class C : I
{
int* opBinaryRight_in(int i)
{
return null;
}
}
Comment #2 by alex — 2012-08-08T03:15:19Z
(In reply to comment #1)
> Your understanding is wrong - templates never go in the vtable.
>
> The solution is to use NVI and forwarding:
>
> interface I
> {
> int* opBinaryRight_in(int i);
>
> int* opBinaryRight(string op : "in")(int i)
> {
> return opBinaryRight_in(i);
> }
> }
>
> class C : I
> {
> int* opBinaryRight_in(int i)
> {
> return null;
> }
> }
I could understand if the opBinaryRight template wasn't constrained to "in", but it is, so I see no reason why it cannot be in the vtable since it can only ever have one instance in a class.
The NVI solution works, but it's very ugly.
Comment #3 by alex — 2012-08-08T03:15:50Z
Changing to enhancement.
Comment #4 by issues.dlang — 2012-08-08T10:11:34Z
> I could understand if the opBinaryRight template wasn't constrained to "in",
but it is, so I see no reason why it cannot be in the vtable since it can only
ever have one instance in a class.
Because templated functions _never_ end up in the vtable. Mixed in templates may if they're fully instantiated when mixed in (I don't remember), but a templated function written directly in the class is _never_ virtual.
That doesn't necessarily mean that there are no situations where the language could be enhanced to make a templated function virtual if it's actually restricted enough (and this may be such a case), but as it stands, being a template is enough to make it non-virtual regardless of what it does or how constrained it is or isn't. I don't believe that even
int func()() { return 2; }
would be virtual, and that's pretty much as constrained as it gets.
Of course, if such a function _did_ get changed to virtual, then it would always defined, whereas right now it's only defined if used, which could be a definite negative, depending on the programmer's intent. So, there's defintely a tradeoff here even if it's possible to make some templated functions virtual.
Comment #5 by robert.schadek — 2024-12-13T18:00:54Z