Thread overview
Variadic template parameters T... bounding
Feb 02, 2016
Voitech
Feb 02, 2016
Daniel Kozak
Feb 02, 2016
Marc Schütz
Feb 02, 2016
Marc Schütz
Feb 02, 2016
Daniel Kozak
Feb 02, 2016
Marc Schütz
Feb 02, 2016
Daniel Kozak
Feb 02, 2016
Marc Schütz
Feb 02, 2016
Voitech
February 02, 2016
Hi, Is it possible to bound T... in template with some type ? For single Parameter declaration it can be done by T:SomeType but variadics does not seems to have that possibility ?
Cheers
February 02, 2016
On Tuesday, 2 February 2016 at 13:20:33 UTC, Voitech wrote:
> Hi, Is it possible to bound T... in template with some type ? For single Parameter declaration it can be done by T:SomeType but variadics does not seems to have that possibility ?
> Cheers

import std.stdio;
import std.meta: allSatisfy;
import std.traits;

void some(T...)(T Args) if (allSatisfy!(isIntegral,T)) {
    writeln(Args);
}

void main()
{
    some(1);
    some(1,2,3);
    some(1,2,3.0); // error
}
February 02, 2016
On Tuesday, 2 February 2016 at 13:20:33 UTC, Voitech wrote:
> Hi, Is it possible to bound T... in template with some type ? For single Parameter declaration it can be done by T:SomeType but variadics does not seems to have that possibility ?
> Cheers

Two possible solutions... If you don't need to know the number of arguments at compile time, you can use normal variadic arguments:

    void test(T)(T[] args...) {
        import std.stdio;
        writeln(T.stringof);
    }

    class A     { }
    class B : A { }
    class C : A { }

    void main()
    {
        test(1,2,3);    // int
        test(4,5,6.9);  // double
        static assert(!__traits(compiles, test(1,"xyz",9)));
        // unfortunately, this doesn't work either:
        //test(new B(), new C());
    }

The last call should work IMO, but it doesn't. I believe that's a compiler bug.

The other solution is to use `CommonType` as a template constraint:

    import std.traits;

    void test(T...)(T args)
    if(!is(CommonType!T == void))
    {
        import std.stdio;
        writeln(T.stringof);
    }

    class A     { }
    class B : A { }
    class C : A { }

    void main()
    {
        test(1,2,3);            // (int, int, int)
        test(4,5,6.9);          // (int, int, double)
        static assert(!__traits(compiles, test(1,"xyz",9)));
        test(new B(), new C()); // (B, C)
    }

As you can see, here the types don't need to match exactly, but they need to have a common base type.
February 02, 2016
On Tuesday, 2 February 2016 at 13:52:55 UTC, Marc Schütz wrote:
> The last call should work IMO, but it doesn't. I believe that's a compiler bug.

Filed:
https://issues.dlang.org/show_bug.cgi?id=15640
February 02, 2016
On Tuesday, 2 February 2016 at 13:57:54 UTC, Marc Schütz wrote:
> On Tuesday, 2 February 2016 at 13:52:55 UTC, Marc Schütz wrote:
>> The last call should work IMO, but it doesn't. I believe that's a compiler bug.
>
> Filed:
> https://issues.dlang.org/show_bug.cgi?id=15640

I would say it is not a bug
test!A(new B(), new C()); // works
which is what I expected
February 02, 2016
On Tuesday, 2 February 2016 at 13:52:55 UTC, Marc Schütz wrote:
> On Tuesday, 2 February 2016 at 13:20:33 UTC, Voitech wrote:
>> [...]
>
> Two possible solutions... If you don't need to know the number of arguments at compile time, you can use normal variadic arguments:
>
> [...]

Thank you I'll try that.
February 02, 2016
On Tuesday, 2 February 2016 at 14:12:54 UTC, Daniel Kozak wrote:
> On Tuesday, 2 February 2016 at 13:57:54 UTC, Marc Schütz wrote:
>> On Tuesday, 2 February 2016 at 13:52:55 UTC, Marc Schütz wrote:
>>> The last call should work IMO, but it doesn't. I believe that's a compiler bug.
>>
>> Filed:
>> https://issues.dlang.org/show_bug.cgi?id=15640
>
> I would say it is not a bug
> test!A(new B(), new C()); // works
> which is what I expected

The bug is that `T` is not automatically inferred to be `A`. That's not a restriction of type inference in general: if you mix ints and floats, the common type is deduced correctly, just not for classes.
February 02, 2016
On Tuesday, 2 February 2016 at 14:47:43 UTC, Marc Schütz wrote:
> On Tuesday, 2 February 2016 at 14:12:54 UTC, Daniel Kozak wrote:
>> On Tuesday, 2 February 2016 at 13:57:54 UTC, Marc Schütz wrote:
>>> On Tuesday, 2 February 2016 at 13:52:55 UTC, Marc Schütz wrote:
>>>> The last call should work IMO, but it doesn't. I believe that's a compiler bug.
>>>
>>> Filed:
>>> https://issues.dlang.org/show_bug.cgi?id=15640
>>
>> I would say it is not a bug
>> test!A(new B(), new C()); // works
>> which is what I expected
>
> if you mix ints and floats, the common type is deduced correctly:

this is a bug for me :). I do not like this. I am ok with (u)byte to int conversion and similar, but mixing float and integral types does not seems to be OK.
February 02, 2016
On Tuesday, 2 February 2016 at 14:55:42 UTC, Daniel Kozak wrote:
> On Tuesday, 2 February 2016 at 14:47:43 UTC, Marc Schütz wrote:
>> if you mix ints and floats, the common type is deduced correctly:
>
> this is a bug for me :). I do not like this. I am ok with (u)byte to int conversion and similar, but mixing float and integral types does not seems to be OK.

I see. But it's also consistent with array type deduction elsewhere:

    auto a = [1, 2.5];
    pragma(msg, typeof(a));  // double[]

... and more importantly:

    class A { }
    class B : A { }
    class C : A { }
    auto a = [new A(), new B()];
    pragma(msg, typeof(a));  // A[]