Thread overview
How do I simulate variadic parameters for template (range) functions?
Aug 24, 2011
Andrej Mitrovic
Aug 24, 2011
Timon Gehr
Aug 24, 2011
Timon Gehr
Aug 24, 2011
Jonathan M Davis
Aug 25, 2011
Jacob Carlborg
August 24, 2011
Here's what I can do with a variadic function:

void main()
{
    int[] a = [ 1, 2, 4, 7, 7, 2, 4, 7, 3, 5];

    process(a[a.countUntil(7) .. $]);
    process(1);
}

void process(int[] vals...)
{
    foreach (val; vals)
    {
    }
}

Very simple, pass one or multiple arguments. But then I thought about using the `until` template instead of countUntil. However `until` returns a range. So my next guess was to write:

void main()
{
    int[] a = [ 1, 2, 4, 7, 7, 2, 4, 7, 3, 5];

    process(a.until(7));  // ok
    process(4);  // error since 4 is not a range
}

void process(Range)(Range vals) if (isInputRange!Range &&
is(ElementType!Range == int))
{
    foreach (val; vals)
    {
    }
}

Is it somehow possible to automatically convert a literal to a range? I really miss the convenience of variadic functions. I thought about making an overload that only takes an int and constructing a simple input range around it so it can be passed to process(), e.g.:

void process(Range)(Range vals) if (isInputRange!Range &&
is(ElementType!Range == int))
{
    foreach (val; vals)
    {
    }
}

void process(int arg)
{
    process(makeInputRange(arg));  // make an input range, pass to
above process()
}

But I can't overload templated and non-templated functions, I think this is one of those old-standing bugs.
August 24, 2011
On 08/24/2011 07:40 PM, Andrej Mitrovic wrote:
> Here's what I can do with a variadic function:
>
> void main()
> {
>      int[] a = [ 1, 2, 4, 7, 7, 2, 4, 7, 3, 5];
>
>      process(a[a.countUntil(7) .. $]);
>      process(1);
> }
>
> void process(int[] vals...)
> {
>      foreach (val; vals)
>      {
>      }
> }
>
> Very simple, pass one or multiple arguments. But then I thought about
> using the `until` template instead of countUntil. However `until`
> returns a range. So my next guess was to write:
>
> void main()
> {
>      int[] a = [ 1, 2, 4, 7, 7, 2, 4, 7, 3, 5];
>
>      process(a.until(7));  // ok
>      process(4);  // error since 4 is not a range
> }
>
> void process(Range)(Range vals) if (isInputRange!Range&&
> is(ElementType!Range == int))
> {
>      foreach (val; vals)
>      {
>      }
> }
>
> Is it somehow possible to automatically convert a literal to a range?
> I really miss the convenience of variadic functions. I thought about
> making an overload that only takes an int and constructing a simple
> input range around it so it can be passed to process(), e.g.:
>
> void process(Range)(Range vals) if (isInputRange!Range&&
> is(ElementType!Range == int))
> {
>      foreach (val; vals)
>      {
>      }
> }
>
> void process(int arg)
> {
>      process(makeInputRange(arg));  // make an input range, pass to
> above process()
> }
>
> But I can't overload templated and non-templated functions, I think
> this is one of those old-standing bugs.

Workaround: You can make it a templated function with no template arguments and wrap a non-templated version, if it is important that the implementation is not a template.





August 24, 2011
On Wed, 24 Aug 2011 13:40:38 -0400, Andrej Mitrovic <andrej.mitrovich@gmail.com> wrote:

> Here's what I can do with a variadic function:
>
> void main()
> {
>     int[] a = [ 1, 2, 4, 7, 7, 2, 4, 7, 3, 5];
>
>     process(a[a.countUntil(7) .. $]);
>     process(1);
> }
>
> void process(int[] vals...)
> {
>     foreach (val; vals)
>     {
>     }
> }
>
> Very simple, pass one or multiple arguments. But then I thought about
> using the `until` template instead of countUntil. However `until`
> returns a range. So my next guess was to write:
>
> void main()
> {
>     int[] a = [ 1, 2, 4, 7, 7, 2, 4, 7, 3, 5];
>
>     process(a.until(7));  // ok
>     process(4);  // error since 4 is not a range
> }
>
> void process(Range)(Range vals) if (isInputRange!Range &&
> is(ElementType!Range == int))
> {
>     foreach (val; vals)
>     {
>     }
> }
>
> Is it somehow possible to automatically convert a literal to a range?
> I really miss the convenience of variadic functions. I thought about
> making an overload that only takes an int and constructing a simple
> input range around it so it can be passed to process(), e.g.:
>
> void process(Range)(Range vals) if (isInputRange!Range &&
> is(ElementType!Range == int))
> {
>     foreach (val; vals)
>     {
>     }
> }
>
> void process(int arg)
> {
>     process(makeInputRange(arg));  // make an input range, pass to
> above process()
> }
>
> But I can't overload templated and non-templated functions, I think
> this is one of those old-standing bugs.

maybe:

void process(Range)(Range vals) if (isInputRange!Range && is(ElementType!Range == int))
{
   ...
}

void process(Vals...)(Vals vals) if (allValsElementsAreInt)
{
   ...
}

Note that I'm not sure what to put for allValsElementsAreInt...

-Steve
August 24, 2011
On 08/24/2011 07:54 PM, Steven Schveighoffer wrote:
> On Wed, 24 Aug 2011 13:40:38 -0400, Andrej Mitrovic
> <andrej.mitrovich@gmail.com> wrote:
>
>> Here's what I can do with a variadic function:
>>
>> void main()
>> {
>> int[] a = [ 1, 2, 4, 7, 7, 2, 4, 7, 3, 5];
>>
>> process(a[a.countUntil(7) .. $]);
>> process(1);
>> }
>>
>> void process(int[] vals...)
>> {
>> foreach (val; vals)
>> {
>> }
>> }
>>
>> Very simple, pass one or multiple arguments. But then I thought about
>> using the `until` template instead of countUntil. However `until`
>> returns a range. So my next guess was to write:
>>
>> void main()
>> {
>> int[] a = [ 1, 2, 4, 7, 7, 2, 4, 7, 3, 5];
>>
>> process(a.until(7)); // ok
>> process(4); // error since 4 is not a range
>> }
>>
>> void process(Range)(Range vals) if (isInputRange!Range &&
>> is(ElementType!Range == int))
>> {
>> foreach (val; vals)
>> {
>> }
>> }
>>
>> Is it somehow possible to automatically convert a literal to a range?
>> I really miss the convenience of variadic functions. I thought about
>> making an overload that only takes an int and constructing a simple
>> input range around it so it can be passed to process(), e.g.:
>>
>> void process(Range)(Range vals) if (isInputRange!Range &&
>> is(ElementType!Range == int))
>> {
>> foreach (val; vals)
>> {
>> }
>> }
>>
>> void process(int arg)
>> {
>> process(makeInputRange(arg)); // make an input range, pass to
>> above process()
>> }
>>
>> But I can't overload templated and non-templated functions, I think
>> this is one of those old-standing bugs.
>
> maybe:
>
> void process(Range)(Range vals) if (isInputRange!Range &&
> is(ElementType!Range == int))
> {
> ...
> }
>
> void process(Vals...)(Vals vals) if (allValsElementsAreInt)
> {
> ...
> }
>
> Note that I'm not sure what to put for allValsElementsAreInt...
>
> -Steve

This should do (although it would probably be even better to have a forAll template and a predicate template).

template allElementsAreInt(T...){
    static if(T.length==0) enum allElementsAreInt=true;
    else enum allElementsAreInt=is(typeof(T[0])==int)
              && allElementsAreInt!(T[1..$]);
}


August 24, 2011
On Wednesday, August 24, 2011 11:00 Timon Gehr wrote:
> On 08/24/2011 07:54 PM, Steven Schveighoffer wrote:
> > On Wed, 24 Aug 2011 13:40:38 -0400, Andrej Mitrovic
> > 
> > <andrej.mitrovich@gmail.com> wrote:
> >> Here's what I can do with a variadic function:
> >> 
> >> void main()
> >> {
> >> int[] a = [ 1, 2, 4, 7, 7, 2, 4, 7, 3, 5];
> >> 
> >> process(a[a.countUntil(7) .. $]);
> >> process(1);
> >> }
> >> 
> >> void process(int[] vals...)
> >> {
> >> foreach (val; vals)
> >> {
> >> }
> >> }
> >> 
> >> Very simple, pass one or multiple arguments. But then I thought about using the `until` template instead of countUntil. However `until` returns a range. So my next guess was to write:
> >> 
> >> void main()
> >> {
> >> int[] a = [ 1, 2, 4, 7, 7, 2, 4, 7, 3, 5];
> >> 
> >> process(a.until(7)); // ok
> >> process(4); // error since 4 is not a range
> >> }
> >> 
> >> void process(Range)(Range vals) if (isInputRange!Range &&
> >> is(ElementType!Range == int))
> >> {
> >> foreach (val; vals)
> >> {
> >> }
> >> }
> >> 
> >> Is it somehow possible to automatically convert a literal to a range? I really miss the convenience of variadic functions. I thought about making an overload that only takes an int and constructing a simple input range around it so it can be passed to process(), e.g.:
> >> 
> >> void process(Range)(Range vals) if (isInputRange!Range &&
> >> is(ElementType!Range == int))
> >> {
> >> foreach (val; vals)
> >> {
> >> }
> >> }
> >> 
> >> void process(int arg)
> >> {
> >> process(makeInputRange(arg)); // make an input range, pass to
> >> above process()
> >> }
> >> 
> >> But I can't overload templated and non-templated functions, I think this is one of those old-standing bugs.
> > 
> > maybe:
> > 
> > void process(Range)(Range vals) if (isInputRange!Range &&
> > is(ElementType!Range == int))
> > {
> > ...
> > }
> > 
> > void process(Vals...)(Vals vals) if (allValsElementsAreInt)
> > {
> > ...
> > }
> > 
> > Note that I'm not sure what to put for allValsElementsAreInt...
> > 
> > -Steve
> 
> This should do (although it would probably be even better to have a forAll template and a predicate template).
> 
> template allElementsAreInt(T...){
> static if(T.length==0) enum allElementsAreInt=true;
> else enum allElementsAreInt=is(typeof(T[0])==int)
> && allElementsAreInt!(T[1..$]);
> }

std.typetuple has anySatisfy and allSatisfy (though that's a rather bizarre place to put them IMHO).

- Jonathan M Davis
August 25, 2011
On 2011-08-24 19:40, Andrej Mitrovic wrote:
> Here's what I can do with a variadic function:
>
> void main()
> {
>      int[] a = [ 1, 2, 4, 7, 7, 2, 4, 7, 3, 5];
>
>      process(a[a.countUntil(7) .. $]);
>      process(1);
> }
>
> void process(int[] vals...)
> {
>      foreach (val; vals)
>      {
>      }
> }
>
> Very simple, pass one or multiple arguments. But then I thought about
> using the `until` template instead of countUntil. However `until`
> returns a range. So my next guess was to write:
>
> void main()
> {
>      int[] a = [ 1, 2, 4, 7, 7, 2, 4, 7, 3, 5];
>
>      process(a.until(7));  // ok
>      process(4);  // error since 4 is not a range
> }
>
> void process(Range)(Range vals) if (isInputRange!Range&&
> is(ElementType!Range == int))
> {
>      foreach (val; vals)
>      {
>      }
> }
>
> Is it somehow possible to automatically convert a literal to a range?
> I really miss the convenience of variadic functions. I thought about
> making an overload that only takes an int and constructing a simple
> input range around it so it can be passed to process(), e.g.:
>
> void process(Range)(Range vals) if (isInputRange!Range&&
> is(ElementType!Range == int))
> {
>      foreach (val; vals)
>      {
>      }
> }
>
> void process(int arg)
> {
>      process(makeInputRange(arg));  // make an input range, pass to
> above process()
> }
>
> But I can't overload templated and non-templated functions, I think
> this is one of those old-standing bugs.

Use a variadic template function and check if the first argument is a range or not.

-- 
/Jacob Carlborg