digitalmars.D.learn - How do I simulate variadic parameters for template (range) functions?
- Andrej Mitrovic (47/47) Aug 24 2011 Here's what I can do with a variadic function:
- Timon Gehr (4/51) Aug 24 2011 Workaround: You can make it a templated function with no template
- Steven Schveighoffer (14/61) Aug 24 2011 maybe:
- Timon Gehr (8/80) Aug 24 2011 This should do (although it would probably be even better to have a
- Jonathan M Davis (4/92) Aug 24 2011 std.typetuple has anySatisfy and allSatisfy (though that's a rather biza...
- Jacob Carlborg (5/52) Aug 24 2011 Use a variadic template function and check if the first argument is a
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.
Aug 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.
Aug 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
Aug 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: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..$]); }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
Aug 24 2011
On Wednesday, August 24, 2011 11:00 Timon Gehr wrote:On 08/24/2011 07:54 PM, Steven Schveighoffer wrote:std.typetuple has anySatisfy and allSatisfy (though that's a rather bizarre place to put them IMHO). - Jonathan M DavisOn Wed, 24 Aug 2011 13:40:38 -0400, Andrej Mitrovic <andrej.mitrovich gmail.com> wrote: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..$]); }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
Aug 24 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
Aug 24 2011