Issue 337 - Function templates cannot be overloaded
Summary: Function templates cannot be overloaded
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D1 (retired)
Hardware: All All
: P2 enhancement
Assignee: Walter Bright
URL:
Keywords: spec
Depends on:
Blocks:
 
Reported: 2006-09-10 10:16 UTC by Mikola Lysenko
Modified: 2019-05-16 08:47 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Mikola Lysenko 2006-09-10 10:16:38 UTC
Two overloaded template functions with the same template signature will cause a name conflict.  Here is an example:

//----

import std.stdio;

void testfunc(T)(T a)
{
    writefln("a = %s", a);
}

void testfunc(T)(int x, T a)
{
    writefln("x = %d, a = %s", x, a);
}

void main()
{
    testfunc("test1");
    testfunc(10, "test2");
}

//----

In this situation there is a name conflict between the two overloads of testfunc since their templates have the exact same signature.  One solution is to wrap them both inside a single template as follows:

//----
template testfunc(T)
{
    void testfunc(T a) { ... }
    void testfunc(int x, T a) { ... }
}

//----

However, testfunc is no longer considered a function template after such an operation, and IFTI is no longer applied.  This approach also prevents other modules from performing an overload on testfunc, such as declaring something like:

//----
void testfunc(T)(int x, int y, T a)
{
    writefln("x = %d, y = %d, a = %s", x, y, a);
}
//----

This will result in a name conflict with the previous declarations.  One solution is to add all of the types in testfunc to the template specification like this:

//----
void testfunc(Tx : int, Ta)(Tx x, Ta a)
{
    writefln("x = %d, a = %s", x, a);
}
//----

Unfortunately this gives the error:

modname.d(xx): template modname.testfunc(Tx : int,Ta) specialization not allowed for deduced parameter Tx


The situation becomes even worse if the type of Tx is deduced from Ta, such as a delegate or another template instance:

void foreach_wrapper(T)(T[] a, void delegate(inout T) dg);
void foreach_wrapper(T)(T[] a, void delegate(int, inout T) dg);
Comment 1 Bruno Medeiros 2006-09-26 05:47:37 UTC
Saying this is IFTI related isn't exactly accurate. Since the problem occurs at template definition, no instantiation is need (implicit or explicit). 

I'm not sure this is a bug (an enhancement perhaps). The spec is not explicit, but only functions can be overloaded, or templates with different specializations. Templated functions are templates foremost (not functions), so they can only be overloaded if the specialization is different, which is not the case.
However I think the following workarounds work (without loss of functionality) :

* For overload based on number of parameters only:
--------
import std.stdio;

void testfunc(T)(T a) {
    writefln("a = %s", a);
}

void testfunc(DUMMY = void, T)(int x, T a) {
    writefln("x = %d, a = %s", x, a);
}

void main() {
    testfunc("test1");
    testfunc(10, "test2");
}
----

* For any kind of overload (just make dummy specializations):
--------
void foreach_wrapper(T)(T[] a, void delegate(inout T) dg) { }
void foreach_wrapper(DUMMY : int=int, T)(T[] a, void delegate(int, T) dg) {
    pragma(msg, "Second specialization");
}
void foreach_wrapper(DUMMY : char=char, T)(T[] a, void delegate(char, T) dg) {
    pragma(msg, "Third specialization");
}

void main()
{
    void delegate(int, inout byte) dg1;
    foreach_wrapper(new byte[3], dg1);

    void delegate(char, inout byte) dg2;
    foreach_wrapper(new byte[3], dg2);
}
----
Comment 2 Walter Bright 2006-10-25 17:46:32 UTC
I agree with Bruno. While it isn't pretty, the workarounds he presented get us past the problem.
Comment 3 Bill Baxter 2006-12-17 02:42:01 UTC
(In reply to comment #2)
> I agree with Bruno. While it isn't pretty, the workarounds he presented get us
> past the problem.
> 

So why can't this sort of workaround be applied automatically by the compiler.  The need to stick a dummy parameter in to work around the inability to overload templates is about as FAR from obvious as it gets.
Comment 4 Lars Ivar Igesund 2008-06-11 02:20:11 UTC
IFTI is next to useless without properly working overload of ifti functions.
Comment 5 Walter Bright 2008-06-13 04:10:33 UTC
//----
void testfunc(Tx : int, Ta)(Tx x, Ta a)
{
    writefln("x = %d, a = %s", x, a);
}
//----

works with current versions of both D1.0 and D2.0.
Comment 6 Stewart Gordon 2012-01-01 15:53:53 UTC
I agree with the analysis - two templates can't have the same signature.  So it would be a matter of changing the language to allow it if they can be instantiated in a way that disambiguates them.
Comment 7 RazvanN 2019-05-16 08:47:40 UTC
The problem does not manifest in D2. Closing as FIXED.