Thread overview
Static strings in templates
May 02, 2008
Janice Caron
May 02, 2008
Leonard Dahlmann
May 02, 2008
downs
May 02, 2008
Christopher Wright
May 02, 2008
Sean Kelly
May 02, 2008
Sean Kelly
May 02, 2008
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
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
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
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
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
== 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?
> 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.

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