Thread overview | ||||||||
---|---|---|---|---|---|---|---|---|
|
August 24, 2011 How do I simulate variadic parameters for template (range) functions? | ||||
---|---|---|---|---|
| ||||
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 Re: How do I simulate variadic parameters for template (range) functions? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrej Mitrovic | 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 Re: How do I simulate variadic parameters for template (range) functions? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrej Mitrovic | 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 Re: How do I simulate variadic parameters for template (range) functions? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | 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 Re: How do I simulate variadic parameters for template (range) functions? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timon Gehr | 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 Re: How do I simulate variadic parameters for template (range) functions? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrej Mitrovic | 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 |
Copyright © 1999-2021 by the D Language Foundation