Thread overview | |||||||||
---|---|---|---|---|---|---|---|---|---|
|
July 31, 2007 Function overloading | ||||
---|---|---|---|---|
| ||||
Hi there, Why not to allow template function overloading? Like void test (T) (T) { } void test (int) { } |
July 31, 2007 Re: Function overloading | ||||
---|---|---|---|---|
| ||||
Posted in reply to Vladimir | 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
|
July 31, 2007 Re: Function overloading | ||||
---|---|---|---|---|
| ||||
Posted in reply to Regan Heath | 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)
|
July 31, 2007 Re: Function overloading | ||||
---|---|---|---|---|
| ||||
Posted in reply to Frits van Bommel | 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
|
July 31, 2007 Re: Function overloading | ||||
---|---|---|---|---|
| ||||
Posted in reply to Regan Heath | 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? |
July 31, 2007 Re: Function overloading | ||||
---|---|---|---|---|
| ||||
Posted in reply to Vladimir | 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 |
July 31, 2007 Re: Function overloading | ||||
---|---|---|---|---|
| ||||
Posted in reply to Regan Heath | 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++
|
Copyright © 1999-2021 by the D Language Foundation