www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Static strings in templates

reply "Janice Caron" <caron800 googlemail.com> writes:
I don't know if this is a bug or not. Someone please help me out.
Here's the deal. Suppose I declare:

    int foo(T)(T s, T t)

with the expectation that the template will be passed a couple of
strings, wstrings or dstring. All works fine if I do

    string s;
    string t;
    int n = foo(s,t);

However, the template can't be instantiated with

    int n = foo("abcde","fg");

because the type of the first argument is invariant(char)[5u], and the
type of the second argument is invariant(char)[2u], and the compiler
can't figure out that both can (and should) be implicitly cast to
invariant(char)[].

It occurs to me that even with only a single parameter, passing string
literals to templated string function will lead to a lot of template
bloat, if the template always considers the argument type to be
invariant(char)[N] (for some N), as opposed to simply
invariant(char)[].

Is this a bug? Can anything be done about this? Is there a workaround?
May 02 2008
next sibling parent reply Leonard Dahlmann <leo.dahlmann gmail.com> writes:
Janice Caron Wrote:

 I don't know if this is a bug or not. Someone please help me out.
 Here's the deal. Suppose I declare:
 
     int foo(T)(T s, T t)
 
 with the expectation that the template will be passed a couple of
 strings, wstrings or dstring. All works fine if I do
 
     string s;
     string t;
     int n = foo(s,t);
 
 However, the template can't be instantiated with
 
     int n = foo("abcde","fg");
 
 because the type of the first argument is invariant(char)[5u], and the
 type of the second argument is invariant(char)[2u], and the compiler
 can't figure out that both can (and should) be implicitly cast to
 invariant(char)[].
 
 It occurs to me that even with only a single parameter, passing string
 literals to templated string function will lead to a lot of template
 bloat, if the template always considers the argument type to be
 invariant(char)[N] (for some N), as opposed to simply
 invariant(char)[].
 
 Is this a bug? Can anything be done about this? Is there a workaround?

I think a workaround is to use downs' Unstatic template. Given a static array type, it returns the corresponding dynamic array type. template Unstatic(T) { alias T Unstatic; } template Unstatic(T : T[]) { alias T[] Unstatic; } int foo(T)(Unstatic!(T) s, Unstatic!(T) t)
May 02 2008
parent downs <default_357-line yahoo.de> writes:
Leonard Dahlmann wrote:
 Janice Caron Wrote:
 
 I don't know if this is a bug or not. Someone please help me out.
 Here's the deal. Suppose I declare:

     int foo(T)(T s, T t)

 with the expectation that the template will be passed a couple of
 strings, wstrings or dstring. All works fine if I do

     string s;
     string t;
     int n = foo(s,t);

 However, the template can't be instantiated with

     int n = foo("abcde","fg");

 because the type of the first argument is invariant(char)[5u], and the
 type of the second argument is invariant(char)[2u], and the compiler
 can't figure out that both can (and should) be implicitly cast to
 invariant(char)[].

 It occurs to me that even with only a single parameter, passing string
 literals to templated string function will lead to a lot of template
 bloat, if the template always considers the argument type to be
 invariant(char)[N] (for some N), as opposed to simply
 invariant(char)[].

 Is this a bug? Can anything be done about this? Is there a workaround?

I think a workaround is to use downs' Unstatic template. Given a static array type, it returns the corresponding dynamic array type. template Unstatic(T) { alias T Unstatic; } template Unstatic(T : T[]) { alias T[] Unstatic; } int foo(T)(Unstatic!(T) s, Unstatic!(T) t)

A better way may be to accept _any_ parameter, as in, int foo(T...)(T stuff); Then check if is(typeof(stuff[0][]) == typeof(stuff[1][])), else static assert(false, "Parameters don't expose full slices of the same type!"); Using unstatic probably breaks ifti. Although, I haven't tested it. ^^ --downs
May 02 2008
prev sibling next sibling parent Christopher Wright <dhasenan gmail.com> writes:
Janice Caron wrote:
<snip>
 However, the template can't be instantiated with
 
     int n = foo("abcde","fg");
 
 because the type of the first argument is invariant(char)[5u], and the
 type of the second argument is invariant(char)[2u], and the compiler
 can't figure out that both can (and should) be implicitly cast to
 invariant(char)[].

I'd call it a compiler bug since static arrays are, as you say, implicitly convertible to dynamic ones. Of course, you could just call it with: int n = foo("abcde"[], "fg");
May 02 2008
prev sibling next sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
Janice Caron wrote:
 I don't know if this is a bug or not. Someone please help me out.
 Here's the deal. Suppose I declare:
 
     int foo(T)(T s, T t)
 
 with the expectation that the template will be passed a couple of
 strings, wstrings or dstring. All works fine if I do
 
     string s;
     string t;
     int n = foo(s,t);
 
 However, the template can't be instantiated with
 
     int n = foo("abcde","fg");
 
 because the type of the first argument is invariant(char)[5u], and the
 type of the second argument is invariant(char)[2u], and the compiler
 can't figure out that both can (and should) be implicitly cast to
 invariant(char)[].

I think this should work: int foo(T)( T[] s, T[] t ); If you want it to accept types other than arrays, however, then things get a bit more complicated: int foo(T,U)( T s, U t ) { static if( isStaticArray!(T) || isStaticArray!(U) ) return foo_!(ElemTypeOf!(T)[])( s, t ); else return foo_!(T)( s, t ); } int foo_(T)( T s, T t );
 It occurs to me that even with only a single parameter, passing string
 literals to templated string function will lead to a lot of template
 bloat, if the template always considers the argument type to be
 invariant(char)[N] (for some N), as opposed to simply
 invariant(char)[].
 
 Is this a bug? Can anything be done about this? Is there a workaround?

It's not a bug, though it would be nice if there were some way to force parameters to dynamic arrays a bit easier. Perhaps if the parameter were 'const', 'invariant', or 'in' it could be done automatically, since the length restriction is unnecessary in that case. Sean
May 02 2008
parent Sean Kelly <sean invisibleduck.org> writes:
== Quote from Sean Kelly (sean invisibleduck.org)'s article
 Janice Caron wrote:
 It occurs to me that even with only a single parameter, passing string
 literals to templated string function will lead to a lot of template
 bloat, if the template always considers the argument type to be
 invariant(char)[N] (for some N), as opposed to simply
 invariant(char)[].

 Is this a bug? Can anything be done about this? Is there a workaround?

parameters to dynamic arrays a bit easier. Perhaps if the parameter were 'const', 'invariant', or 'in' it could be done automatically, since the length restriction is unnecessary in that case.

Scratch that. In D 2.0, array literals could be automatically passed as invariant(T)[], since that will produce the correct behavior in each case. Static arrays could be passed as dynamic arrays in cases where the parameter they are passed to is not out or inout. This latter bit is somewhat of a special case though, and I abhor special cases. Sean
May 02 2008
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Janice Caron" wrote
I don't know if this is a bug or not. Someone please help me out.
 Here's the deal. Suppose I declare:

    int foo(T)(T s, T t)

 with the expectation that the template will be passed a couple of
 strings, wstrings or dstring. All works fine if I do

    string s;
    string t;
    int n = foo(s,t);

 However, the template can't be instantiated with

    int n = foo("abcde","fg");

 because the type of the first argument is invariant(char)[5u], and the
 type of the second argument is invariant(char)[2u], and the compiler
 can't figure out that both can (and should) be implicitly cast to
 invariant(char)[].

 It occurs to me that even with only a single parameter, passing string
 literals to templated string function will lead to a lot of template
 bloat, if the template always considers the argument type to be
 invariant(char)[N] (for some N), as opposed to simply
 invariant(char)[].

 Is this a bug? Can anything be done about this? Is there a workaround?

I think the workaround is to do foo("abcde"[], "fg"); But I have logged a bug for something similar: http://d.puremagic.com/issues/show_bug.cgi?id=1817 I think if the compiler template generation always generated template code for X[] instead of X[5], it would fix both our problems. -Steve
May 02 2008