Function overloading

Vladimir v.voinkov at gmail.com
Tue Jul 31 05:44:41 PDT 2007


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++


More information about the Digitalmars-d-learn mailing list