April 26 [Issue 24522] New: Formation and inference of nested type sequences | ||||
---|---|---|---|---|
| ||||
https://issues.dlang.org/show_bug.cgi?id=24522 Issue ID: 24522 Summary: Formation and inference of nested type sequences Product: D Version: D2 Hardware: All OS: All Status: NEW Severity: major Priority: P1 Component: dmd Assignee: nobody@puremagic.com Reporter: qs.il.paperinik@gmail.com For a function template, `f(Ts...)(ref Ts args)` works as intended: The number and `ref`-ness of parameters can be inferred from arguments. This works because `ref` is a storage class. If we replace `ref` by ´const`, it works as well: ```d void f(Ts...)(const Ts args) { static foreach (alias arg; args) { pragma(msg, typeof(arg)); } } void main() { int i; f(&i, &i); } ``` Prints ``` const(int*) const(int*) ``` as expected. Use a type constructor instead of a storage class: ```d void f(Ts...)(const(Ts) args) { static foreach (alias arg; args) { pragma(msg, typeof(arg)); } } void main() { int i; f(&i, &i); } ``` Prints ``` int* int* ``` Const is completely ignored! Coming from C++, one would assume that the following works: ```d void f(Ts...)(Ts* args) { static foreach (alias arg; args) { pragma(msg, typeof(arg)); } } void main() { int i; f(&i, &i); } ``` But it fails: ``` Error: template `onlineapp.f` is not callable using argument types `!()(int*, int*)` ``` And it’s not that the compiler just can’t do the inference, providing arguments explicitly: ```d void main() { int i; f!(int, int)(&i, &i); } ``` Fails with the following error: ``` Error: cannot have pointer to `(int, int)` ``` Even weirder, using slice types: Inference fails, but using explicit template arguments: ```d void f(Ts...)(Ts[] args) { static foreach (alias arg; args) { pragma(msg, typeof(arg)); } } void main() { int i; f!(int, int)([i], [i]); } ``` The template instantiation succeeds, it prints ``` int int ``` which is weird, and then fails with an error: ``` Error: template `onlineapp.f` is not callable using argument types `!()(int[], int[])` ``` Other, probably less thought-of type suffixes are function pointer and delegate types: ```d void f(Ts...)(Ts function(int) args) { static foreach (alias arg; args) pragma(msg, typeof(arg)); } void main() { int i; f((int x) => x); } ``` Fails: ``` Error: template `onlineapp.f` is not callable using argument types `!()(int function(int x) pure nothrow @nogc @safe)` ``` And with explicit template arguments: ```d void f(Ts...)(Ts function(int) args) { static foreach (alias arg; args) pragma(msg, typeof(arg)); } void main() { int i; f!int(x => x); } ``` Also fails: ``` Error: functions cannot return a sequence (use `std.typecons.Tuple`) ``` My sense is that when a type tuple is to be inferred and type constructors and type suffixes are applied to it, that should expand element-wise: `const(Ts)[]` expands to `(const(T[0])[],...,const(T[$-1])[])`, and inferring the length and elements of `Ts` should work as well: Inferring the length is trivial, and if the length is inferred, inferring the element types should work as well, since it works for single parameters. -- |
Copyright © 1999-2021 by the D Language Foundation