It seems all Andrei's usages of the feature in std.algorithm have an
alias parameter as the first, followed by the variadic.
So maybe this is just a code path in the compiler that hasn't been
tickled previously.
Does your code work if you make the first param an alias?

This is the thing Walter made work in D2 but not D1.
http://d.puremagic.com/issues/show_bug.cgi?id=493
You can sorta work around it by using nested templates. Then you can
get a calling syntax like
alloc!(C).D1_4ever;
alloc!(C).D1_4ever(1,2);
--bb

It seems all Andrei's usages of the feature in std.algorithm have an
alias parameter as the first, followed by the variadic.
So maybe this is just a code path in the compiler that hasn't been
tickled previously.
Does your code work if you make the first param an alias?
--bb

I dug this case a bit more in 2.019. First of all, it's possible to
make it work for non-zero argument count by making a single change in
the template body:
T alloc(T, Params ...)( Params params )
{
cast(void) params;
return new T( params );
}
though it stops accepting zero arguments because "tuple has no effect in
expression (tuple())". The weirdest part is when you try to access
number of arguments in the tuple:
void main()
{
auto d = alloc!(C)( 1, 2 );
}
T alloc(T, Params ...)( Params params )
{
cast(void) params;
pragma( msg, Params.length.stringof );
return new T( params );
}
when compiling, prints:
0u
2u
but without the cast:
0u
test.d(12): Error: expected 0 arguments, not 2
So it instantiates the template once, check whether the tuple argument
is explicitly used inside the template body, then instantiates it again
with number of arguments depending on the previous instantiation. Looks
to me like a dirty hack in the compiler.