www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Function overloading

reply Vladimir <v.voinkov gmail.com> writes:
Hi there,

Why not to allow template function overloading? Like

void test (T) (T)
{
}

void test (int)
{
}
Jul 31 2007
parent reply Regan Heath <regan netmail.co.nz> writes:
Vladimir wrote:
 Hi there,
 
 Why not to allow template function overloading? Like
 
 void test (T) (T)
 {
 }
 
 void test (int)
 {
 }

It is: import std.stdio; void test(T)(T p) { writefln("misc called"); } void test(T : int)(T p) { writefln("int called"); } void main() { int i; long l; float f; test!(int)(i); test!(long)(l); test!(float)(f); } Output: int called misc called misc called However, without the !(int) etc it fails to compile with: "template tplspec.test(T : int) specialization not allowed for deduced parameter T" Given the documentation: <copy> Argument Deduction The types of template parameters are deduced for a particular template instantiation by comparing the template argument with the corresponding template parameter. For each template parameter, the following rules are applied in order until a type is deduced for each parameter: 1. If there is no type specialization for the parameter, the type of the parameter is set to the template argument. 2. If the type specialization is dependent on a type parameter, the type of that parameter is set to be the corresponding part of the type argument. 3. If after all the type arguments are examined there are any type parameters left with no type assigned, they are assigned types corresponding to the template argument in the same position in the TemplateArgumentList. 4. If applying the above rules does not result in exactly one type for each template parameter, then it is an error. </copy> It seems that for the first call "foo(i)" step #1 does nothing, step #2 sets the type to 'int', step #3 does nothing and step #4 finds that there _is_ exactly 1 type per argument so why the error? Is this a bug? Regan
Jul 31 2007
parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Regan Heath wrote:
 import std.stdio;
 
 void test(T)(T p)
 {
     writefln("misc called");
 }
 
 void test(T : int)(T p)
 {
     writefln("int called");
 }
 
 void main()
 {
     int i;
     long l;
     float f;
     test!(int)(i);
     test!(long)(l);
     test!(float)(f);
 }
 
 Output:
 int called
 misc called
 misc called
 
 
 However, without the !(int) etc it fails to compile with: "template 
 tplspec.test(T : int) specialization not allowed for deduced parameter T"

Workaround: --- import std.stdio; void testImpl(T)(T p) { writefln("misc called"); } void testImpl(T : int)(T p) { writefln("int called"); } void test(T)(T p) { return testImpl!(T)(p); } void main() { int i; long l; float f; test(i); test(l); test(f); } --- (test uses the deduced parameter to explicitly instantiate testImpl)
Jul 31 2007
parent reply Regan Heath <regan netmail.co.nz> writes:
Frits van Bommel wrote:
 Regan Heath wrote:
 import std.stdio;

 void test(T)(T p)
 {
     writefln("misc called");
 }

 void test(T : int)(T p)
 {
     writefln("int called");
 }

 void main()
 {
     int i;
     long l;
     float f;
     test!(int)(i);
     test!(long)(l);
     test!(float)(f);
 }

 Output:
 int called
 misc called
 misc called


 However, without the !(int) etc it fails to compile with: "template 
 tplspec.test(T : int) specialization not allowed for deduced parameter T"

Workaround: --- import std.stdio; void testImpl(T)(T p) { writefln("misc called"); } void testImpl(T : int)(T p) { writefln("int called"); } void test(T)(T p) { return testImpl!(T)(p); } void main() { int i; long l; float f; test(i); test(l); test(f); } --- (test uses the deduced parameter to explicitly instantiate testImpl)

Nice! Regan
Jul 31 2007
parent reply Vladimir <v.voinkov gmail.com> writes:
Ok, it works for that case.

I'm playing with string template parameters. It's a kind of miracle for me, a
c++ programmer. I made a precompiled wildcard match and would like static
version to overload as follows:

bool wildcardMatch (T : char[]) (T wild, T str) // general case
{
    return false;
}

bool wildcardMatch (char[] W) (T str) // static case
{
    return false;
}

void main()
{
    wildcardMatch ("*", "123");
    wildcardMatch !("*") ("123");
}

Is that posible?
Jul 31 2007
parent reply Regan Heath <regan netmail.co.nz> writes:
Vladimir wrote:
 Ok, it works for that case.
 
 I'm playing with string template parameters. It's a kind of miracle
 for me, a c++ programmer. I made a precompiled wildcard match and
 would like static version to overload as follows:
 
 bool wildcardMatch (T : char[]) (T wild, T str) // general case { 
 return false; }
 
 bool wildcardMatch (char[] W) (T str) // static case { return false; 
 }
 
 void main() { wildcardMatch ("*", "123"); wildcardMatch !("*")
 ("123"); }
 
 Is that posible?

At first I thought, maybe "static if" would be better than a template specialization, i.e. bool wildcardMatch (T : char[]) (T wild, T str) { static if (wild == "*") return true; return false; } but of course the value of 'wild' is not known at compile time... or is it? If it's a constant as in your example 'main' above then it is and the compiler could theoretically evaluate it. But then I thought, if you know it's "*" why make a call to wildcardMatch at all? (after all it will always match) I came up with: bool someOtherTpl (T : char[]) (T wild, T str, bool something) { if (something) wildcardMatch(wild, str); } someOtherTpl("*", ... which is a case where you have to code the call to wildcardMatch because you don't know wild was "*" at that point. The closest I managed to get with template specialization is: import std.stdio; bool wildcardMatch (T) (T wild, T str) // general case { writefln("general case"); return false; } bool wildcardMatch (W:invariant(char[1]), S) (W wild, S str) // "*" case { writefln("* case"); return false; } void main() { wildcardMatch!(char[])("*asd*".dup, "123".dup); wildcardMatch!(invariant(char[1]),char[])("*", "123".dup); wildcardMatch!(invariant(char[1]),char[])("a", "123".dup); } Which incorrectly calls the * case for the wild string "a" because of course it is specializing using a static array of 1 character. Regan
Jul 31 2007
parent Vladimir <v.voinkov gmail.com> writes:
Regan Heath Wrote:

 Vladimir wrote:
 Ok, it works for that case.
 
 I'm playing with string template parameters. It's a kind of miracle
 for me, a c++ programmer. I made a precompiled wildcard match and
 would like static version to overload as follows:
 
 bool wildcardMatch (T : char[]) (T wild, T str) // general case { 
 return false; }
 
 bool wildcardMatch (char[] W) (T str) // static case { return false; 
 }
 
 void main() { wildcardMatch ("*", "123"); wildcardMatch !("*")
 ("123"); }
 
 Is that posible?

At first I thought, maybe "static if" would be better than a template specialization, i.e. bool wildcardMatch (T : char[]) (T wild, T str) { static if (wild == "*") return true; return false; } but of course the value of 'wild' is not known at compile time... or is it? If it's a constant as in your example 'main' above then it is and the compiler could theoretically evaluate it. But then I thought, if you know it's "*" why make a call to wildcardMatch at all? (after all it will always match) I came up with: bool someOtherTpl (T : char[]) (T wild, T str, bool something) { if (something) wildcardMatch(wild, str); } someOtherTpl("*", ... which is a case where you have to code the call to wildcardMatch because you don't know wild was "*" at that point. The closest I managed to get with template specialization is: import std.stdio; bool wildcardMatch (T) (T wild, T str) // general case { writefln("general case"); return false; } bool wildcardMatch (W:invariant(char[1]), S) (W wild, S str) // "*" case { writefln("* case"); return false; } void main() { wildcardMatch!(char[])("*asd*".dup, "123".dup); wildcardMatch!(invariant(char[1]),char[])("*", "123".dup); wildcardMatch!(invariant(char[1]),char[])("a", "123".dup); } Which incorrectly calls the * case for the wild string "a" because of course it is specializing using a static array of 1 character. Regan

import std.string; bool wildcardMatch (char[] E) (char[] aString) { return Expression !(E).Result.match (aString); } private { const int TypeEmpty = 0; const int TypeAsterisk = 1; const int TypeQuestion = 2; const int TypeChar = 3; // int expressionType (char[] aExpression) { if (aExpression.length == 0) return TypeEmpty; if (aExpression [0] == '*') return TypeAsterisk; if (aExpression [0] == '?') return TypeQuestion; return TypeChar; } // char[] headExpression (char[] aExpression) { return aExpression [0 .. length - tailExpression (aExpression).length]; } // char[] tailExpression (char[] aExpression) { int type = TypeEmpty; for (int i = 0; i < aExpression.length; ++i) { if (i == 0) { switch (aExpression [i]) { case '*': type = TypeAsterisk; break; case '?': type = TypeQuestion; break; default: type = TypeChar; } } else if (type == TypeAsterisk) { if (aExpression [i] != '*') return aExpression [i .. length]; } else if (type == TypeQuestion) { if (aExpression [i] != '?') return aExpression [i .. length]; } else { if (aExpression [i] == '*' || aExpression [i] == '?') return aExpression [i .. length]; } } return ""; } template Expression (char[] E) { static if (expressionType (E) == TypeAsterisk) alias AsteriksMatch !(E) Result; else static if (expressionType (E) == TypeQuestion) alias QuestionMatch !(E) Result; else static if (expressionType (E) == TypeChar) alias CharMatch !(E) Result; else alias EmptyMatch !(E) Result; } template AsteriksMatch (char[] E) { static assert (expressionType (E) == TypeAsterisk); bool match (char[] aString) { const char[] Tail = tailExpression (E); static if (Tail.length == 0) return true; for (int i = aString.length; i >= 0; --i) { if (Expression !(Tail).Result.match (aString [i .. length])) return true; } return false; } } template QuestionMatch (char[] E) { static assert (expressionType (E) == TypeQuestion); bool match (char[] aString) { const char[] Head = headExpression (E); if (aString.length == Head.length) return true; if (aString.length < Head.length) return false; const char[] Tail = tailExpression (E); return Expression !(Tail).Result.match (aString [Head.length .. length]); } } template CharMatch (char[] E) { static assert (expressionType (E) == TypeChar); bool match (char[] aString) { const char[] Head = headExpression (E); if (aString.length < Head.length) return false; if (icmp (Head, aString [0 .. Head.length]) != 0) return false; const char[] Tail = tailExpression (E); return Expression !(Tail).Result.match (aString [Head.length .. length]); } } template EmptyMatch (char[] E) { static assert (expressionType (E) == TypeEmpty); bool match (char[] aString) { return aString.length == 0; } } } It can be used with any expresion known at compile time: char[] checkme = "123456"; wildcardMatch !("???5*") (checkme); wildcardMatch !("1???5*") (checkme); wildcardMatch !("?????????5*") (checkme); I dont know how it could be useful, it's just a toy. Surprisingly, I can't freely overload functions like in C++
Jul 31 2007