ApplyRight

ApplyRight does a partial application of its arguments, providing a way to bind a set of arguments to the given template while delaying actually instantiating that template until the full set of arguments is provided. The "Right" in the name indicates that the initial arguments are one the right-hand side of the argument list when the given template is instantiated.

Essentially, ApplyRight results in a template that stores Template and Args, and when that intermediate template is instantiated in turn, it instantiates Template with the arguments to the intermediate template on the left-hand side and with Args on the right-hand side - i.e. Args is applied to the right when instantiating Template.

So, if you have

alias Intermediate = ApplyRight!(MyTemplate, Arg1, Arg2);
alias Result = Intermediate!(ArgA, ArgB);

then that is equivalent to

alias Result = MyTemplate!(ArgA, ArgB, Arg1, Arg2);

with the difference being that you have an intermediate template which can be stored or passed to other templates (e.g. as a template predicate).

The only difference between ApplyLeft and ApplyRight is whether Args is on the left-hand or the right-hand side of the arguments given to Template when it's instantiated.

template ApplyRight (
alias Template
Args...
) {}

Examples

1 {
2     alias Intermediate = ApplyRight!(AliasSeq, ubyte, ushort, uint);
3     alias Result = Intermediate!(char, wchar, dchar);
4     static assert(is(Result == AliasSeq!(char, wchar, dchar, ubyte, ushort, uint)));
5 }
6 {
7     enum isImplicitlyConvertible(T, U) = is(T : U);
8 
9     // i.e. isImplicitlyConvertible!(T, short) is what Filter is checking
10     // for with each element in the AliasSeq.
11     static assert(is(Filter!(ApplyRight!(isImplicitlyConvertible, short),
12                              ubyte, string, short, float, int) ==
13                      AliasSeq!(ubyte, short)));
14 }
15 {
16     enum hasMember(T, string member) = __traits(hasMember, T, member);
17 
18     struct S1
19     {
20         bool foo;
21     }
22 
23     struct S2
24     {
25         int foo() { return 42; }
26     }
27 
28     static assert(all!(ApplyRight!(hasMember, "foo"), S1, S2));
29 }
30 {
31     // Either set of arguments can be empty, since the first set is just
32     // stored to be applied later, and then when the intermediate template
33     // is instantiated, they're all applied to the given template in the
34     // requested order. However, whether the code compiles when
35     // instantiating the intermediate template depends on what kinds of
36     // arguments the given template requires.
37 
38     alias Intermediate1 = ApplyRight!AliasSeq;
39     static assert(Intermediate1!().length == 0);
40 
41     enum isSameSize(T, U) = T.sizeof == U.sizeof;
42 
43     alias Intermediate2 = ApplyRight!(isSameSize, int);
44     static assert(Intermediate2!uint);
45 
46     alias Intermediate3 = ApplyRight!(isSameSize, int, uint);
47     static assert(Intermediate3!());
48 
49     alias Intermediate4 = ApplyRight!(isSameSize);
50     static assert(Intermediate4!(int, uint));
51 
52     // isSameSize requires two arguments
53     alias Intermediate5 = ApplyRight!isSameSize;
54     static assert(!__traits(compiles, Intermediate5!()));
55     static assert(!__traits(compiles, Intermediate5!int));
56 }

See Also

Meta