www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Template function that accept strings and array of strings

reply "badlink" <andrea.9940 gmail.com> writes:
Hello, I can't figure how to write a template function that 
accept either strings or array of strings.

This is my current code:

bool hasItemParent(T)(const(char)[] itemId, const(T)[] parentId)
if (is(typeof(T) == char) || (isArray!T && is(typeof(T[]) == 
char)))
{...}

I used const(T)[] because I'd like to accept immutable and 
mutable strings.
But calling it with an immutable string generate this error:

Error: template cache.MetadataCache.hasItemParent cannot deduce 
function from argument types !()(string, string), candidates are:
cache.MetadataCache.hasItemParent(T)(const(char)[] itemId, 
const(T)[] parentId) if (is(typeof(T) == char))

Any suggestions ?
Jul 15 2015
next sibling parent "Vlad Levenfeld" <vlevenfeld gmail.com> writes:
On Wednesday, 15 July 2015 at 21:57:50 UTC, badlink wrote:
 Hello, I can't figure how to write a template function that 
 accept either strings or array of strings.

 This is my current code:

 bool hasItemParent(T)(const(char)[] itemId, const(T)[] parentId)
 if (is(typeof(T) == char) || (isArray!T && is(typeof(T[]) == 
 char)))
 {...}

 I used const(T)[] because I'd like to accept immutable and 
 mutable strings.
 But calling it with an immutable string generate this error:

 Error: template cache.MetadataCache.hasItemParent cannot deduce 
 function from argument types !()(string, string), candidates 
 are:
 cache.MetadataCache.hasItemParent(T)(const(char)[] itemId, 
 const(T)[] parentId) if (is(typeof(T) == char))

 Any suggestions ?
T is already a type, so typeof(T) is an error, which makes the constraint fail. Try hasItemParent(T)(const(char)[] itemId, const(T)[] parentId) if (is(T == char) || is (T == char[])) at least I think that's what you meant. typeof(anything[]) will never == char.
Jul 15 2015
prev sibling next sibling parent "Yuxuan Shui" <yshuiv7 gmail.com> writes:
On Wednesday, 15 July 2015 at 21:57:50 UTC, badlink wrote:
 Hello, I can't figure how to write a template function that 
 accept either strings or array of strings.

 This is my current code:

 bool hasItemParent(T)(const(char)[] itemId, const(T)[] parentId)
 if (is(typeof(T) == char) || (isArray!T && is(typeof(T[]) == 
 char)))
 {...}

 I used const(T)[] because I'd like to accept immutable and 
 mutable strings.
 But calling it with an immutable string generate this error:

 Error: template cache.MetadataCache.hasItemParent cannot deduce 
 function from argument types !()(string, string), candidates 
 are:
 cache.MetadataCache.hasItemParent(T)(const(char)[] itemId, 
 const(T)[] parentId) if (is(typeof(T) == char))

 Any suggestions ?
T is already a type, you don't need to typeof() it. This should work: bool hasItemParent(T)(const(char)[] itemId, const(T)[] parentId) if (is(T == char) || (isArray!T && is(ElementType!T == char)))
Jul 15 2015
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2015-07-15 23:57, badlink wrote:
 Hello, I can't figure how to write a template function that accept
 either strings or array of strings.

 This is my current code:

 bool hasItemParent(T)(const(char)[] itemId, const(T)[] parentId)
 if (is(typeof(T) == char) || (isArray!T && is(typeof(T[]) == char)))
 {...}

 I used const(T)[] because I'd like to accept immutable and mutable strings.
 But calling it with an immutable string generate this error:

 Error: template cache.MetadataCache.hasItemParent cannot deduce function
 from argument types !()(string, string), candidates are:
 cache.MetadataCache.hasItemParent(T)(const(char)[] itemId, const(T)[]
 parentId) if (is(typeof(T) == char))

 Any suggestions ?
If I understand you correctly, I think you want a type safe variadic function: void foo (const(char[])[] args ...) { writeln(args); } void main() { foo("foo", "bar"); foo("foo".dup, "bar".dup); auto a = ["foo", "bar"]; foo(a); auto b = ["foo".dup, "bar".dup]; foo(b); } -- /Jacob Carlborg
Jul 15 2015
parent reply "badlink" <andrea.9940 gmail.com> writes:
Thank you for all answers.

Removing typeof do resolve the problem when the second parameter 
is a simple string.
However when passing an array of string the error still occur:
Error: template cache.MetadataCache.hasItemParent cannot deduce 
function from argument types !()(string, string[]).

The method with the variadic function works, but I would have to 
use only one parameter because this doesn't work:
fun(const(char[])[] a, const(char[])[] b ...)
and is a bit ugly in my use case ...

After some tests I found that:
if (is(T == char) || is(T == string))
works, so I assume the problem is the immutable nature of string 
that breaks the type checking.

What should I use to enable this function to accept all 
combinations char[], const(char)[], and immutable(char) ?
Jul 16 2015
parent reply Jacob Carlborg <doob me.com> writes:
On 2015-07-16 18:49, badlink wrote:

 The method with the variadic function works, but I would have to use
 only one parameter because this doesn't work:
 fun(const(char[])[] a, const(char[])[] b ...)
 and is a bit ugly in my use case ...
I don't think I really understand how you want to use/call the function. Could you give an example with all the different types you want to call the function? -- /Jacob Carlborg
Jul 17 2015
parent reply "badlink" <andrea.9940 gmail.com> writes:
On Friday, 17 July 2015 at 12:58:58 UTC, Jacob Carlborg wrote:
 I don't think I really understand how you want to use/call the 
 function. Could you give an example with all the different 
 types you want to call the function?
My fault, I didn't test the variadic function enough and jumped to conclusion. It actually works well http://pastebin.com/R4EHuBLh
Jul 17 2015
parent Jacob Carlborg <doob me.com> writes:
On 2015-07-17 19:25, badlink wrote:

 My fault, I didn't test the variadic function enough and jumped to
 conclusion.
 It actually works well http://pastebin.com/R4EHuBLh
Cool :) Sometimes D developers think templates will be needed to solve everything. -- /Jacob Carlborg
Jul 17 2015
prev sibling parent reply "Gary Willoughby" <dev nomad.so> writes:
On Wednesday, 15 July 2015 at 21:57:50 UTC, badlink wrote:
 Hello, I can't figure how to write a template function that 
 accept either strings or array of strings.

 This is my current code:

 bool hasItemParent(T)(const(char)[] itemId, const(T)[] parentId)
 if (is(typeof(T) == char) || (isArray!T && is(typeof(T[]) == 
 char)))
 {...}

 I used const(T)[] because I'd like to accept immutable and 
 mutable strings.
 But calling it with an immutable string generate this error:

 Error: template cache.MetadataCache.hasItemParent cannot deduce 
 function from argument types !()(string, string), candidates 
 are:
 cache.MetadataCache.hasItemParent(T)(const(char)[] itemId, 
 const(T)[] parentId) if (is(typeof(T) == char))

 Any suggestions ?
Something like this: import std.stdio; import std.traits; import std.range; bool hasItemParent(A, B)(A itemId, B parentId) if (isSomeString!(A) && (isSomeString!(B) || isArray!(B) && isSomeString!(ElementType!(B)))) { writefln("%s", typeof(parentId).stringof); return true; } void main(string[] args) { string one = "foo"; char[] two = "foo".dup; const(char)[] three = "foo"; immutable(char)[] four = "foo"; string[] five = ["foo", "bar"]; char[][] six = ["foo".dup, "bar".dup]; const(char)[][] seven = ["foo", "bar"]; immutable(char)[][] eight = ["foo", "bar"]; hasItemParent(one, one); hasItemParent(two, two); hasItemParent(three, three); hasItemParent(four, four); hasItemParent(one, five); hasItemParent(two, six); hasItemParent(three, seven); hasItemParent(four, eight); }
Jul 16 2015
next sibling parent "Gary Willoughby" <dev nomad.so> writes:
Also checkout inout functions:

http://dlang.org/function.html#inout-functions
Jul 16 2015
prev sibling parent reply "badlink" <andrea.9940 gmail.com> writes:
On Thursday, 16 July 2015 at 18:41:47 UTC, Gary Willoughby wrote:
 bool hasItemParent(A, B)(A itemId, B parentId)
 if (isSomeString!(A) && (isSomeString!(B) || isArray!(B) && 
 isSomeString!(ElementType!(B))))
Thank you ! I completely missed isSomeString. I think the definition can be safely shortened to: bool hasItemParent(T)(const(char)[] itemId, T parentId) if (isSomeString!T || isSomeString!(ElementType!T)) Minor flaw, as it is the function also accepts wchar[] and dchar[] that break the compilation because I do comparisons with char[].
Jul 16 2015
parent "badlink" <andrea.9940 gmail.com> writes:
After a thorough reading of the documentation I found an even 
simpler solution:

bool hasItemParent(T)(const(char)[] itemId, T parentId)
if (is(T : const(char)[]) || is(T : const(char[])[]))
{ ... }

Now it accepts all these: char[], const(char)[], 
immutable(char)[], char[][], const(char)[][] ,immutable(char)[][] 
but not their wchar and dchar counterparts.
Jul 16 2015