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

Reply via email to