On 3/8/18 3:29 AM, Shachar Shemesh wrote:
On 07/03/18 17:11, Steven Schveighoffer wrote:
Well, you could do it with templates, but obviously that is less
desirable:
void func2(Args...)(Args args) if(is(typeof(func(args)))) { return
func(args); }
I never understood why anyone would use "is" for checking compilability
when we have "__triats(compiles, func(args))".
There are some subtle differences in the past which caused me not to use
__traits(compiles).
I don't remember what they are, maybe it's a bias that needs reexamining.
With that aside, I would urge you not to use this test. It makes the
error case worse. Check this out:
void func1(int a) {
}
void func2(Args...)(Args args) if( __traits(compiles, func1(args))) {
func1(args);
}
void func3(Args...)(Args args) {
func1(args);
}
void main() {
long var;
func2(var);
func3(var);
}
Which error would you rather get? Calling func2 results in:
test.d(15): Error: template test.func2 cannot deduce function from
argument types !()(long), candidates are:
test.d(4): test.func2(Args...)(Args args) if (__traits(compiles,
func1(args)))
Calling func3 results in:
test.d(9): Error: function test.func1(int a) is not callable using
argument types (long)
test.d(9): cannot pass argument _param_0 of type long to
parameter int a
test.d(16): Error: template instance `test.func3!long` error instantiating
When calling func3, the compiler is telling you what's wrong (i.e. - you
are passing a long to a function expecting a var). When calling func2,
all you know is that there is some problem.
Either way, you know the error is in calling func1. In most cases, the
error is not so simple, and the template is not so simple, to the point
that I think the first error will be more informative.
It also prevents a problem with template overloading.
With that out of the way, I don't like generating proxy functions with
"Args..." templates. They generate unneeded code bloat:
void main() {
int var1;
ubyte var2;
byte var3;
ushort var4;
short var5;
uint var6;
// This generates 6 instantiations of the same function
func2(var1);
func2(var2);
func2(var3);
func2(var4);
func2(var5);
func2(var6);
}
If I could use Params, there would be only one instantiation.
Yep, hence "obviously that is less desirable."
In an ideal world, there would be a way to remove all traces of func2.
In other words, there would be a way to instruct the compiler to always
inline func2, and not even include it in the resulting object file.
-Steve