1 // Written in the D programming language2 /++
3 Templates to manipulate
4 $(DDSUBLINK spec/template, variadic-templates, template parameter sequences)
5 (also known as $(I alias sequences)).
6 7 Some operations on alias sequences are built into the language,
8 such as `S[i]`, which accesses the element at index `i` in the
9 sequence. `S[low .. high]` returns a new alias
10 sequence that is a slice of the old one.
11 12 For more information, see
13 $(DDLINK ctarguments, Compile-time Sequences, Compile-time Sequences).
14 15 One thing that should be noted is that while the templates provided in this
16 module can be extremely useful, they generally should not be used with lists
17 of values. The language uses alias sequences for a variety of things
18 (including both parameter lists and argument lists), so they can contain
19 types, symbols, values, or a mixture of them all. The ability to manipulate
20 types and symbols within alias sequences is vital, because that's really
21 the only way to do it. However, because D has CTFE (Compile-Time Function
22 Evaluation), making it possible to call many functions at compile time, if
23 code needs to be able to manipulate values at compile-time, CTFE is
24 typically much more efficient and easier to do. Instantiating a bunch of
25 templates to manipulate values is incredibly inefficient in comparison.
26 27 So, while many of the templates in this module will work with values simply
28 because alias sequences can contain values, most code should restrict
29 itself to using them for operating on types or symbols - i.e. the stuff
30 where CTFE can't be used. That being said, there will be times when one can
31 be used to feed into the other. E.G.
32 ---
33 alias Types = AliasSeq!(int, byte, ulong, int[10]);
34 35 enum Sizeof(T) = T.sizeof;
36 37 alias sizesAsAliasSeq = Map!(Sizeof, Types);
38 static assert(sizesAsAliasSeq == AliasSeq!(4, 1, 8, 40));
39 40 enum size_t[] sizes = [sizesAsAliasSeq];
41 static assert(sizes == [4, 1, 8, 40]);
42 ---
43 44 Just be aware that if CTFE can be used for a particular task, it's better to
45 use CTFE than to manipulate alias sequences with the kind of templates
46 provided by this module.
47 48 $(SCRIPT inhibitQuickIndex = 1;)
49 $(DIVC quickindex,
50 $(BOOKTABLE ,
51 $(TR $(TH Category) $(TH Templates))
52 $(TR $(TD Building blocks) $(TD
53 $(LREF Alias)
54 $(LREF AliasSeq)
55 ))
56 $(TR $(TD Alias sequence filtering) $(TD
57 $(LREF Filter)
58 $(LREF Stride)
59 $(LREF Unique)
60 ))
61 $(TR $(TD Alias sequence transformation) $(TD
62 $(LREF Map)
63 $(LREF Reverse)
64 ))
65 $(TR $(TD Alias sequence searching) $(TD
66 $(LREF all)
67 $(LREF any)
68 $(LREF indexOf)
69 ))
70 $(TR $(TD Template predicates) $(TD
71 $(LREF And)
72 $(LREF Not)
73 $(LREF Or)
74 ))
75 $(TR $(TD Template instantiation) $(TD
76 $(LREF ApplyLeft)
77 $(LREF ApplyRight)
78 $(LREF Instantiate)
79 ))
80 )
81 82 References:
83 Based on ideas in Table 3.1 from
84 $(LINK2 http://amazon.com/exec/obidos/ASIN/0201704315/ref=ase_classicempire/102-2957199-2585768,
85 Modern C++ Design),
86 Andrei Alexandrescu (Addison-Wesley Professional, 2001)
87 88 Copyright: Copyright The D Language Foundation 2005 - 2024.
89 License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
90 Authors: $(HTTP digitalmars.com, Walter Bright),
91 $(HTTP klickverbot.at, David Nadlinger)
92 $(HTTP jmdavisprog.com, Jonathan M Davis)
93 Source: $(PHOBOSSRC phobos/sys/meta)
94 +/95 modulephobos.sys.meta;
96 97 // Example for converting types to values from module documentation.98 @safeunittest99 {
100 aliasTypes = AliasSeq!(int, byte, ulong, int[10]);
101 102 enumSizeof(T) = T.sizeof;
103 104 aliassizesAsAliasSeq = Map!(Sizeof, Types);
105 staticassert(sizesAsAliasSeq == AliasSeq!(4, 1, 8, 40));
106 107 enumsize_t[] sizes = [sizesAsAliasSeq];
108 staticassert(sizes == [4, 1, 8, 40]);
109 }
110 111 /++
112 Creates a sequence of zero or more aliases. This is most commonly
113 used as template parameters or arguments.
114 +/115 aliasAliasSeq(TList...) = TList;
116 117 ///118 @safeunittest119 {
120 aliasTL = AliasSeq!(int, double);
121 122 intfoo(TLtd) // same as int foo(int, double);123 {
124 returntd[0] + cast(int) td[1];
125 }
126 }
127 128 ///129 @safeunittest130 {
131 aliasTL = AliasSeq!(int, double);
132 133 aliasTypes = AliasSeq!(TL, char);
134 staticassert(is(Types == AliasSeq!(int, double, char)));
135 }
136 137 ///138 @safeunittest139 {
140 staticcharfoo(size_ti, stringstr)
141 {
142 returnstr[i];
143 }
144 145 aliasvars = AliasSeq!(2, "dlang");
146 147 assert(foo(vars) == 'a');
148 }
149 150 /++
151 Allows aliasing of any single symbol, type or compile-time expression.
152 153 Not everything can be directly aliased. An alias cannot be declared
154 of - for example - a literal:
155 ---
156 alias a = 4; //Error
157 ---
158 With this template any single entity can be aliased:
159 ---
160 alias b = Alias!4; //OK
161 ---
162 See_Also:
163 To alias more than one thing at once, use $(LREF AliasSeq).
164 +/165 aliasAlias(aliasa) = a;
166 167 /// Ditto168 aliasAlias(T) = T;
169 170 ///171 @safeunittest172 {
173 // Without Alias this would fail if Args[0] were e.g. a value and174 // some logic would be needed to detect when to use enum instead.175 aliasHead(Args...) = Alias!(Args[0]);
176 aliasTail(Args...) = Args[1 .. $];
177 178 aliasBlah = AliasSeq!(3, int, "hello");
179 staticassert(Head!Blah == 3);
180 staticassert(is(Head!(Tail!Blah) == int));
181 staticassert((Tail!Blah)[1] == "hello");
182 }
183 184 ///185 @safeunittest186 {
187 {
188 aliasa = Alias!123;
189 staticassert(a == 123);
190 }
191 {
192 enume = 1;
193 aliasa = Alias!e;
194 staticassert(a == 1);
195 }
196 {
197 aliasa = Alias!(3 + 4);
198 staticassert(a == 7);
199 }
200 {
201 aliasconcat = (s0, s1) => s0 ~ s1;
202 aliasa = Alias!(concat("Hello", " World!"));
203 staticassert(a == "Hello World!");
204 }
205 {
206 aliasA = Alias!int;
207 staticassert(is(A == int));
208 }
209 {
210 aliasA = Alias!(AliasSeq!int);
211 staticassert(!is(typeof(A[0]))); // An Alias is not an AliasSeq.212 staticassert(is(A == int));
213 }
214 {
215 autoi = 6;
216 aliasa = Alias!i;
217 ++a;
218 assert(i == 7);
219 }
220 }
221 222 /++
223 Filters an $(D AliasSeq) using the given template predicate.
224 225 The result is an $(D AliasSeq) that contains only the elements which satisfy
226 the predicate.
227 +/228 templateFilter(aliasPred, Args...)
229 {
230 aliasFilter = AliasSeq!();
231 staticforeach (Arg; Args)
232 {
233 staticif (Pred!Arg)
234 Filter = AliasSeq!(Filter, Arg);
235 }
236 }
237 238 ///239 @safeunittest240 {
241 importphobos.sys.traits : isDynamicArray, isPointer, isUnsignedInteger;
242 243 aliasTypes = AliasSeq!(string, int, int[], bool[], ulong, double, ubyte);
244 245 staticassert(is(Filter!(isDynamicArray, Types) ==
246 AliasSeq!(string, int[], bool[])));
247 248 staticassert(is(Filter!(isUnsignedInteger, Types) ==
249 AliasSeq!(ulong, ubyte)));
250 251 staticassert(is(Filter!(isPointer, Types) == AliasSeq!()));
252 }
253 254 /++
255 Evaluates to an $(LREF AliasSeq) which only contains every nth element from
256 the $(LREF AliasSeq) that was passed in, where $(D n) is stepSize.
257 258 So, if stepSize is $(D 2), then the result contains every other element from
259 the original. If stepSize is $(D 3), then the result contains every third
260 element from the original. Etc.
261 262 If stepSize is negative, then the result is equivalent to using
263 $(LREF Reverse) on the given $(LREF AliasSeq) and then using Stride on it
264 with the absolute value of that stepSize.
265 266 If stepSize is positive, then the first element in the original
267 $(LREF AliasSeq) is the first element in the result, whereas if stepSize is
268 negative, then the last element in the original is the first element in the
269 result. Each subsequent element is then the element at the index of the
270 previous element plus stepSize.
271 +/272 templateStride(intstepSize, Args...)
273 if (stepSize != 0)
274 {
275 aliasStride = AliasSeq!();
276 staticif (stepSize > 0)
277 {
278 staticforeach (i; 0 .. (Args.length + stepSize - 1) / stepSize)
279 Stride = AliasSeq!(Stride, Args[i * stepSize]);
280 }
281 else282 {
283 staticforeach (i; 0 .. (Args.length - stepSize - 1) / -stepSize)
284 Stride = AliasSeq!(Stride, Args[$ - 1 + i * stepSize]);
285 }
286 }
287 288 ///289 @safeunittest290 {
291 staticassert(is(Stride!(1, short, int, long) == AliasSeq!(short, int, long)));
292 staticassert(is(Stride!(2, short, int, long) == AliasSeq!(short, long)));
293 staticassert(is(Stride!(3, short, int, long) == AliasSeq!short));
294 staticassert(is(Stride!(100, short, int, long) == AliasSeq!short));
295 296 staticassert(is(Stride!(-1, short, int, long) == AliasSeq!(long, int, short)));
297 staticassert(is(Stride!(-2, short, int, long) == AliasSeq!(long, short)));
298 staticassert(is(Stride!(-3, short, int, long) == AliasSeq!long));
299 staticassert(is(Stride!(-100, short, int, long) == AliasSeq!long));
300 301 aliasTypes = AliasSeq!(short, int, long, ushort, uint, ulong);
302 staticassert(is(Stride!(3, Types) == AliasSeq!(short, ushort)));
303 staticassert(is(Stride!(3, Types[1 .. $]) == AliasSeq!(int, uint)));
304 staticassert(is(Stride!(-3, Types) == AliasSeq!(ulong, long)));
305 306 staticassert(is(Stride!(-2, Types) == Stride!(2, Reverse!Types)));
307 308 staticassert(is(Stride!1 == AliasSeq!()));
309 staticassert(is(Stride!100 == AliasSeq!()));
310 }
311 312 @safeunittest313 {
314 staticassert(!__traits(compiles, Stride!(0, int)));
315 316 aliasTypes = AliasSeq!(bool, byte, ubyte, short, ushort, int, uint, long, ulong,
317 char, wchar, dchar, float, double, real, Object);
318 aliasTypes2 = AliasSeq!(bool, ubyte, ushort, uint, ulong, wchar, float, real);
319 aliasTypes3 = AliasSeq!(bool, short, uint, char, float, Object);
320 aliasTypes4 = AliasSeq!(bool, ushort, ulong, float);
321 aliasTypes5 = AliasSeq!(bool, int, wchar, Object);
322 aliasTypes6 = AliasSeq!(bool, uint, float);
323 aliasTypes7 = AliasSeq!(bool, long, real);
324 aliasTypes8 = AliasSeq!(bool, ulong);
325 aliasTypes9 = AliasSeq!(bool, char);
326 aliasTypes10 = AliasSeq!(bool, wchar);
327 328 staticassert(is(Stride!(1, Types) == Types));
329 staticassert(is(Stride!(2, Types) == Types2));
330 staticassert(is(Stride!(3, Types) == Types3));
331 staticassert(is(Stride!(4, Types) == Types4));
332 staticassert(is(Stride!(5, Types) == Types5));
333 staticassert(is(Stride!(6, Types) == Types6));
334 staticassert(is(Stride!(7, Types) == Types7));
335 staticassert(is(Stride!(8, Types) == Types8));
336 staticassert(is(Stride!(9, Types) == Types9));
337 staticassert(is(Stride!(10, Types) == Types10));
338 339 staticassert(is(Stride!(-1, Types) == Reverse!Types));
340 staticassert(is(Stride!(-2, Types) == Stride!(2, Reverse!Types)));
341 staticassert(is(Stride!(-3, Types) == Stride!(3, Reverse!Types)));
342 staticassert(is(Stride!(-4, Types) == Stride!(4, Reverse!Types)));
343 staticassert(is(Stride!(-5, Types) == Stride!(5, Reverse!Types)));
344 staticassert(is(Stride!(-6, Types) == Stride!(6, Reverse!Types)));
345 staticassert(is(Stride!(-7, Types) == Stride!(7, Reverse!Types)));
346 staticassert(is(Stride!(-8, Types) == Stride!(8, Reverse!Types)));
347 staticassert(is(Stride!(-9, Types) == Stride!(9, Reverse!Types)));
348 staticassert(is(Stride!(-10, Types) == Stride!(10, Reverse!Types)));
349 }
350 351 /++
352 Evaluates to an $(LREF AliasSeq) which contains no duplicate elements.
353 354 Unique takes a binary template predicate that it uses to compare elements
355 for equality. If the predicate is $(D true) when an element in the given
356 $(LREF AliasSeq) is compared with an element with a lower index, then that
357 element is not included in the result (so if any elements in the
358 $(LREF AliasSeq) are considered equal per the predicate, then only the
359 first one is included in the result).
360 361 Note that the binary predicate must be partially instantiable, e.g.
362 ---
363 alias PartialCmp = Cmp!(Args[0]);
364 enum same = PartialCmp!(Args[1]);
365 ---
366 Otherwise, it won't work.
367 368 See_Also:
369 $(REF isSameSymbol, phobos, sys, traits)
370 $(REF isSameType, phobos, sys, traits)
371 +/372 templateUnique(aliasCmp, Args...)
373 {
374 aliasUnique = AliasSeq!();
375 staticforeach (i, Arg; Args)
376 {
377 staticif (i == 0)
378 Unique = AliasSeq!Arg;
379 else380 Unique = AppendIfUnique!(Cmp, Unique, Arg);
381 }
382 }
383 384 // Unfortunately, this can't be done in-place in Unique, because then we get385 // errors about reassigning Unique after reading it.386 privatetemplateAppendIfUnique(aliasCmp, Args...)
387 {
388 staticif (indexOf!(Cmp!(Args[$ - 1]), Args[0 .. $ - 1]) == -1)
389 aliasAppendIfUnique = Args;
390 else391 aliasAppendIfUnique = Args[0 .. $ - 1];
392 }
393 394 ///395 @safeunittest396 {
397 importphobos.sys.traits : isSameType;
398 399 aliasTypes1 = AliasSeq!(int, long, long, int, int, float, int);
400 401 staticassert(is(Unique!(isSameType, Types1) ==
402 AliasSeq!(int, long, float)));
403 404 aliasTypes2 = AliasSeq!(byte, ubyte, short, ushort, int, uint);
405 staticassert(is(Unique!(isSameType, Types2) == Types2));
406 407 // Empty AliasSeq.408 staticassert(Unique!isSameType.length == 0);
409 410 // An AliasSeq with a single element works as well.411 staticassert(Unique!(isSameType, int).length == 1);
412 }
413 414 ///415 @safeunittest416 {
417 importphobos.sys.traits : isSameSymbol;
418 419 inti;
420 strings;
421 realr;
422 aliasSymbols = AliasSeq!(i, s, i, i, s, r, r, i);
423 424 aliasResult = Unique!(isSameSymbol, Symbols);
425 staticassert(Result.length == 3);
426 staticassert(__traits(isSame, Result[0], i));
427 staticassert(__traits(isSame, Result[1], s));
428 staticassert(__traits(isSame, Result[2], r));
429 430 // Comparing AliasSeqs for equality with is expressions only works431 // if they only contain types.432 staticassert(!is(Symbols == Result));
433 }
434 435 ///436 @safeunittest437 {
438 aliasTypes = AliasSeq!(int, uint, long, string, short, int*, ushort);
439 440 templatesameSize(T)
441 {
442 enumsameSize(U) = T.sizeof == U.sizeof;
443 }
444 staticassert(is(Unique!(sameSize, Types) ==
445 AliasSeq!(int, long, string, short)));
446 447 // The predicate must be partially instantiable.448 enumsameSize_fails(T, U) = T.sizeof == U.sizeof;
449 staticassert(!__traits(compiles, Unique!(sameSize_fails, Types)));
450 }
451 452 /++
453 Map takes a template and applies it to every element in the given
454 $(D AliasSeq), resulting in an $(D AliasSeq) with the transformed elements.
455 456 So, it's equivalent to
457 `AliasSeq!(Fun!(Args[0]), Fun!(Args[1]), ..., Fun!(Args[$ - 1]))`.
458 +/459 templateMap(aliasFun, Args...)
460 {
461 aliasMap = AliasSeq!();
462 staticforeach (Arg; Args)
463 Map = AliasSeq!(Map, Fun!Arg);
464 }
465 466 ///467 @safeunittest468 {
469 importphobos.sys.traits : Unqualified;
470 471 // empty472 aliasEmpty = Map!Unqualified;
473 staticassert(Empty.length == 0);
474 475 // single476 aliasSingle = Map!(Unqualified, constint);
477 staticassert(is(Single == AliasSeq!int));
478 479 // several480 aliasSeveral = Map!(Unqualified, int, constint, immutableint, uint,
481 ubyte, byte, short, ushort, constlong);
482 staticassert(is(Several == AliasSeq!(int, int, int, uint,
483 ubyte, byte, short, ushort, long)));
484 485 aliasToDynamicArray(T) = T[];
486 487 aliasArrays = Map!(ToDynamicArray, int, constubyte, string);
488 staticassert(is(Arrays == AliasSeq!(int[], const(ubyte)[], string[])));
489 }
490 491 // @@@ BUG @@@ The test below exposes failure of the straightforward use.492 // See @adamdruppe's comment to https://github.com/dlang/phobos/pull/8039493 @safeunittest494 {
495 templateid(aliaswhat)
496 {
497 enumid = __traits(identifier, what);
498 }
499 500 enumA { a }
501 staticassert(Map!(id, A.a) == AliasSeq!"a");
502 }
503 504 // regression test for https://issues.dlang.org/show_bug.cgi?id=21088505 @systemunittest// typeid opEquals is @system506 {
507 enumgetTypeId(T) = typeid(T);
508 aliasA = Map!(getTypeId, int);
509 510 assert(A == typeid(int));
511 }
512 513 /++
514 Takes an $(D AliasSeq) and result in an $(D AliasSeq) where the order of
515 the elements has been reversed.
516 +/517 templateReverse(Args...)
518 {
519 aliasReverse = AliasSeq!();
520 staticforeach_reverse (Arg; Args)
521 Reverse = AliasSeq!(Reverse, Arg);
522 }
523 524 ///525 @safeunittest526 {
527 staticassert(is(Reverse!(int, byte, long, string) ==
528 AliasSeq!(string, long, byte, int)));
529 530 aliasTypes = AliasSeq!(int, long, long, int, float,
531 ubyte, short, ushort, uint);
532 staticassert(is(Reverse!Types == AliasSeq!(uint, ushort, short, ubyte,
533 float, int, long, long, int)));
534 535 staticassert(is(Reverse!() == AliasSeq!()));
536 }
537 538 /++
539 Whether the given template predicate is $(D true) for all of the elements in
540 the given $(D AliasSeq).
541 542 Evaluation is $(I not) short-circuited if a $(D false) result is
543 encountered; the template predicate must be instantiable with all the
544 elements.
545 +/546 version (StdDdoc) templateall(aliasPred, Args...)
547 {
548 importcore.internal.traits : allSatisfy;
549 aliasall = allSatisfy!(Pred, Args);
550 }
551 else552 {
553 importcore.internal.traits : allSatisfy;
554 aliasall = allSatisfy;
555 }
556 557 ///558 @safeunittest559 {
560 importphobos.sys.traits : isDynamicArray, isInteger;
561 562 staticassert(!all!(isInteger, int, double));
563 staticassert( all!(isInteger, int, long));
564 565 aliasTypes = AliasSeq!(string, int[], bool[]);
566 567 staticassert( all!(isDynamicArray, Types));
568 staticassert(!all!(isInteger, Types));
569 570 staticassert( all!isInteger);
571 }
572 573 /++
574 Whether the given template predicate is $(D true) for any of the elements in
575 the given $(D AliasSeq).
576 577 Evaluation is $(I not) short-circuited if a $(D true) result is
578 encountered; the template predicate must be instantiable with all the
579 elements.
580 +/581 version (StdDdoc) templateany(aliasPred, Args...)
582 {
583 importcore.internal.traits : anySatisfy;
584 aliasany = anySatisfy!(Pred, Args);
585 }
586 else587 {
588 importcore.internal.traits : anySatisfy;
589 aliasany = anySatisfy;
590 }
591 592 ///593 @safeunittest594 {
595 importphobos.sys.traits : isDynamicArray, isInteger;
596 597 staticassert(!any!(isInteger, string, double));
598 staticassert( any!(isInteger, int, double));
599 600 aliasTypes = AliasSeq!(string, int[], bool[], real, bool);
601 602 staticassert( any!(isDynamicArray, Types));
603 staticassert(!any!(isInteger, Types));
604 605 staticassert(!any!isInteger);
606 }
607 608 /++
609 Evaluates to the index of the first element where $(D Pred!(Args[i])) is
610 $(D true).
611 612 If $(D Pred!(Args[i])) is not $(D true) for any elements, then the result
613 is $(D -1).
614 615 Evaluation is $(I not) short-circuited if a $(D true) result is
616 encountered; the template predicate must be instantiable with all the
617 elements.
618 +/619 templateindexOf(aliasPred, Args...)
620 {
621 enumptrdiff_tindexOf =
622 {
623 staticforeach (i; 0 .. Args.length)
624 {
625 staticif (Pred!(Args[i]))
626 returni;
627 }
628 return -1;
629 }();
630 }
631 632 ///633 @safeunittest634 {
635 importphobos.sys.traits : isInteger, isSameSymbol, isSameType;
636 637 aliasTypes1 = AliasSeq!(string, int, long, char[], ubyte, int);
638 aliasTypes2 = AliasSeq!(float, double, int[], char[], void);
639 640 staticassert(indexOf!(isInteger, Types1) == 1);
641 staticassert(indexOf!(isInteger, Types2) == -1);
642 643 staticassert(indexOf!(isSameType!ubyte, Types1) == 4);
644 staticassert(indexOf!(isSameType!ubyte, Types2) == -1);
645 646 inti;
647 intj;
648 strings;
649 intfoo() { return0; }
650 aliasSymbols = AliasSeq!(i, j, foo);
651 staticassert(indexOf!(isSameSymbol!j, Symbols) == 1);
652 staticassert(indexOf!(isSameSymbol!s, Symbols) == -1);
653 654 // Empty AliasSeq.655 staticassert(indexOf!isInteger == -1);
656 657 // The predicate does not compile with all of the arguments,658 // so indexOf does not compile.659 staticassert(!__traits(compiles, indexOf!(isSameType!int, long, int, 42)));
660 }
661 662 unittest663 {
664 importphobos.sys.traits : isSameType;
665 666 staticassert(indexOf!(isSameType!int, short, int, long) >= 0);
667 staticassert(indexOf!(isSameType!string, short, int, long) < 0);
668 669 // This is to verify that we don't accidentally end up with the type of670 // the result differing based on whether it's -1 or not. Not specifying the671 // type at all in indexOf results in -1 being int on all systems and the672 // other results being whatever size_t is (ulong on most systems at this673 // point), which does generally work, but being explicit with the type674 // avoids any subtle issues that might come from the type of the result675 // varying based on whether the item is found or not.676 staticassert(is(typeof(indexOf!(isSameType!int, short, int, long)) ==
677 typeof(indexOf!(isSameType!string, short, int, long))));
678 679 staticassert(indexOf!(isSameType!string, string, string, string, string) == 0);
680 staticassert(indexOf!(isSameType!string, int, string, string, string) == 1);
681 staticassert(indexOf!(isSameType!string, int, int, string, string) == 2);
682 staticassert(indexOf!(isSameType!string, int, int, int, string) == 3);
683 staticassert(indexOf!(isSameType!string, int, int, int, int) == -1);
684 }
685 686 /++
687 Combines multiple template predicates into a single template predicate using
688 logical AND - i.e. for the resulting predicate to be $(D true) with a
689 particular argument, all of the predicates must be $(D true) with that
690 argument.
691 692 Evaluation is $(I not) short-circuited if a $(D false) result is
693 encountered; the template predicate must be instantiable with all the
694 elements.
695 696 See_Also:
697 $(LREF Not)
698 $(LREF Or)
699 +/700 templateAnd(Preds...)
701 {
702 enumAnd(Args...) =
703 {
704 staticforeach (Pred; Preds)
705 {
706 staticif (!Pred!Args)
707 returnfalse;
708 }
709 returntrue;
710 }();
711 }
712 713 ///714 @safeunittest715 {
716 importphobos.sys.traits : isNumeric;
717 718 templateisSameSize(size_tsize)
719 {
720 enumisSameSize(T) = T.sizeof == size;
721 }
722 723 aliasis32BitNumeric = And!(isNumeric, isSameSize!4);
724 725 staticassert(!is32BitNumeric!short);
726 staticassert( is32BitNumeric!int);
727 staticassert(!is32BitNumeric!long);
728 staticassert( is32BitNumeric!float);
729 staticassert(!is32BitNumeric!double);
730 staticassert(!is32BitNumeric!(int*));
731 732 // An empty sequence of predicates always yields true.733 aliasalwaysTrue = And!();
734 staticassert(alwaysTrue!int);
735 }
736 737 /++
738 Predicates with multiple parameters are also supported. However, the number
739 of parameters must match.
740 +/741 @safeunittest742 {
743 importphobos.sys.traits : isImplicitlyConvertible, isInteger, isSameType;
744 745 aliasisOnlyImplicitlyConvertible746 = And!(Not!isSameType, isImplicitlyConvertible);
747 748 staticassert( isOnlyImplicitlyConvertible!(int, long));
749 staticassert(!isOnlyImplicitlyConvertible!(int, int));
750 staticassert(!isOnlyImplicitlyConvertible!(long, int));
751 752 staticassert( isOnlyImplicitlyConvertible!(string, const(char)[]));
753 staticassert(!isOnlyImplicitlyConvertible!(string, string));
754 staticassert(!isOnlyImplicitlyConvertible!(const(char)[], string));
755 756 // Mismatched numbers of parameters.757 aliasdoesNotWork = And!(isInteger, isImplicitlyConvertible);
758 staticassert(!__traits(compiles, doesNotWork!int));
759 staticassert(!__traits(compiles, doesNotWork!(int, long)));
760 }
761 762 @safeunittest763 {
764 enumtestAlways(Args...) = true;
765 enumtestNever(Args...) = false;
766 767 staticassert( Instantiate!(And!(testAlways, testAlways, testAlways), int));
768 staticassert(!Instantiate!(And!(testAlways, testAlways, testNever), int));
769 staticassert(!Instantiate!(And!(testAlways, testNever, testNever), int));
770 staticassert(!Instantiate!(And!(testNever, testNever, testNever), int));
771 staticassert(!Instantiate!(And!(testNever, testNever, testAlways), int));
772 staticassert(!Instantiate!(And!(testNever, testAlways, testAlways), int));
773 774 staticassert( Instantiate!(And!(testAlways, testAlways), int));
775 staticassert(!Instantiate!(And!(testAlways, testNever), int));
776 staticassert(!Instantiate!(And!(testNever, testAlways), int));
777 staticassert(!Instantiate!(And!(testNever, testNever), int));
778 779 staticassert( Instantiate!(And!testAlways, int));
780 staticassert(!Instantiate!(And!testNever, int));
781 782 // No short-circuiting.783 importphobos.sys.traits : isEqual, isFloatingPoint;
784 staticassert(!Instantiate!(And!isFloatingPoint, int));
785 staticassert(!__traits(compiles, Instantiate!(And!(isFloatingPoint, isEqual), int)));
786 }
787 788 /++
789 Evaluates to a template predicate which negates the given predicate.
790 791 See_Also:
792 $(LREF And)
793 $(LREF Or)
794 +/795 templateNot(aliasPred)
796 {
797 enumNot(Args...) = !Pred!Args;
798 }
799 800 ///801 @safeunittest802 {
803 importphobos.sys.traits : isDynamicArray, isPointer;
804 805 aliasisNotPointer = Not!isPointer;
806 staticassert( isNotPointer!int);
807 staticassert(!isNotPointer!(int*));
808 staticassert( all!(isNotPointer, string, char, float));
809 810 staticassert(!all!(Not!isDynamicArray, string, char[], int[], long));
811 staticassert( any!(Not!isDynamicArray, string, char[], int[], long));
812 }
813 814 /++
815 Predicates with multiple parameters are also supported.
816 +/817 @safeunittest818 {
819 importphobos.sys.traits : isImplicitlyConvertible, isInteger;
820 821 aliasnotImplicitlyConvertible = Not!isImplicitlyConvertible;
822 823 staticassert( notImplicitlyConvertible!(long, int));
824 staticassert(!notImplicitlyConvertible!(int, long));
825 826 staticassert( notImplicitlyConvertible!(const(char)[], string));
827 staticassert(!notImplicitlyConvertible!(string, const(char)[]));
828 }
829 830 /++
831 Combines multiple template predicates into a single template predicate using
832 logical OR - i.e. for the resulting predicate to be $(D true) with a
833 particular argument, at least one of the predicates must be $(D true) with
834 that argument.
835 836 Evaluation is $(I not) short-circuited if a $(D true) result is
837 encountered; the template predicate must be instantiable with all the
838 elements.
839 840 See_Also:
841 $(LREF And)
842 $(LREF Not)
843 +/844 templateOr(Preds...)
845 {
846 enumOr(Args...) =
847 {
848 staticforeach (Pred; Preds)
849 {
850 staticif (Pred!Args)
851 returntrue;
852 }
853 returnfalse;
854 }();
855 }
856 857 ///858 @safeunittest859 {
860 importphobos.sys.traits : isFloatingPoint, isSignedInteger;
861 862 aliasisSignedNumeric = Or!(isFloatingPoint, isSignedInteger);
863 864 staticassert( isSignedNumeric!short);
865 staticassert( isSignedNumeric!long);
866 staticassert( isSignedNumeric!double);
867 staticassert(!isSignedNumeric!uint);
868 staticassert(!isSignedNumeric!ulong);
869 staticassert(!isSignedNumeric!string);
870 staticassert(!isSignedNumeric!(int*));
871 872 // An empty sequence of predicates always yields false.873 aliasalwaysFalse = Or!();
874 staticassert(!alwaysFalse!int);
875 }
876 877 /++
878 Predicates with multiple parameters are also supported. However, the number
879 of parameters must match.
880 +/881 @safeunittest882 {
883 importphobos.sys.traits : isImplicitlyConvertible, isInteger;
884 885 enumisSameSize(T, U) = T.sizeof == U.sizeof;
886 aliasconvertibleOrSameSize = Or!(isImplicitlyConvertible, isSameSize);
887 888 staticassert( convertibleOrSameSize!(int, int));
889 staticassert( convertibleOrSameSize!(int, long));
890 staticassert(!convertibleOrSameSize!(long, int));
891 892 staticassert( convertibleOrSameSize!(int, float));
893 staticassert( convertibleOrSameSize!(float, int));
894 staticassert(!convertibleOrSameSize!(double, int));
895 staticassert(!convertibleOrSameSize!(float, long));
896 897 staticassert( convertibleOrSameSize!(int*, string*));
898 899 // Mismatched numbers of parameters.900 aliasdoesNotWork = Or!(isInteger, isImplicitlyConvertible);
901 staticassert(!__traits(compiles, doesNotWork!int));
902 staticassert(!__traits(compiles, doesNotWork!(int, long)));
903 }
904 905 @safeunittest906 {
907 enumtestAlways(Args...) = true;
908 enumtestNever(Args...) = false;
909 910 staticassert( Instantiate!(Or!(testAlways, testAlways, testAlways), int));
911 staticassert( Instantiate!(Or!(testAlways, testAlways, testNever), int));
912 staticassert( Instantiate!(Or!(testAlways, testNever, testNever), int));
913 staticassert(!Instantiate!(Or!(testNever, testNever, testNever), int));
914 915 staticassert( Instantiate!(Or!(testAlways, testAlways), int));
916 staticassert( Instantiate!(Or!(testAlways, testNever), int));
917 staticassert( Instantiate!(Or!(testNever, testAlways), int));
918 staticassert(!Instantiate!(Or!(testNever, testNever), int));
919 920 staticassert( Instantiate!(Or!testAlways, int));
921 staticassert(!Instantiate!(Or!testNever, int));
922 923 staticassert(Instantiate!(Or!testAlways, int));
924 staticassert(Instantiate!(Or!testAlways, Map));
925 staticassert(Instantiate!(Or!testAlways, int, Map));
926 927 // No short-circuiting.928 importphobos.sys.traits : isEqual, isInteger;
929 staticassert( Instantiate!(Or!isInteger, int));
930 staticassert(!__traits(compiles, Instantiate!(Or!(isInteger, isEqual), int)));
931 }
932 933 /++
934 Instantiates the given template with the given arguments and evaluates to
935 the result of that template.
936 937 This is used to work around some syntactic limitations that D has with
938 regards to instantiating templates. Essentially, D requires a name for a
939 template when instantiating it (be it the name of the template itself or an
940 alias to the template), which causes problems when you don't have that.
941 942 Specifically, if the template is within an $(LREF AliasSeq) - e.g.
943 $(D Templates[0]!Args) - or it's the result of another template - e.g
944 $(D Foo!Bar!Baz) - the instantiation is illegal. This leaves two ways to
945 solve the problem. The first is to create an alias, e.g.
946 ---
947 alias Template = Templates[0];
948 enum result = Template!Args;
949 950 alias Partial = Foo!Bar;
951 alias T = Partial!Baz;
952 ---
953 The second is to use Instantiate, e.g.
954 ---
955 enum result = Instantiate!(Templates[0], Args);
956 957 alias T = Instiantiate!(Foo!Bar, Baz);
958 ---
959 960 Of course, the downside to this is that it adds an additional template
961 instantiation, but it avoids creating an alias just to be able to
962 instantiate a template. So, whether it makes sense to use Instantiate
963 instead of an alias naturally depends on the situation, but without it,
964 we'd be forced to create aliases even in situations where that's
965 problematic.
966 967 See_Also:
968 $(LREF ApplyLeft)
969 $(LREF ApplyRight)
970 +/971 aliasInstantiate(aliasTemplate, Args...) = Template!Args;
972 973 ///974 @safeunittest975 {
976 importphobos.sys.traits : ConstOf, isImplicitlyConvertible, isSameType, isInteger;
977 978 aliasTemplates = AliasSeq!(isImplicitlyConvertible!int,
979 isSameType!string,
980 isInteger,
981 ConstOf);
982 983 // Templates[0]!long does not compile, because the compiler can't parse it.984 985 staticassert( Instantiate!(Templates[0], long));
986 staticassert(!Instantiate!(Templates[0], string));
987 988 staticassert(!Instantiate!(Templates[1], long));
989 staticassert( Instantiate!(Templates[1], string));
990 991 staticassert( Instantiate!(Templates[2], long));
992 staticassert(!Instantiate!(Templates[2], string));
993 994 staticassert(is(Instantiate!(Templates[3], int) == constint));
995 staticassert(is(Instantiate!(Templates[3], double) == constdouble));
996 }
997 998 ///999 @safeunittest1000 {
1001 templatehasMember(stringmember)
1002 {
1003 enumhasMember(T) = __traits(hasMember, T, member);
1004 }
1005 1006 structS1007 {
1008 intfoo;
1009 }
1010 1011 // hasMember!"foo"!S does not compile,1012 // because having multiple ! arguments is not allowed.1013 1014 staticassert( Instantiate!(hasMember!"foo", S));
1015 staticassert(!Instantiate!(hasMember!"bar", S));
1016 }
1017 1018 /++
1019 Instantiate also allows us to do template instantations via templates that
1020 take other templates as arguments.
1021 +/1022 @safeunittest1023 {
1024 importphobos.sys.traits : isInteger, isNumeric, isUnsignedInteger;
1025 1026 aliasResults = Map!(ApplyRight!(Instantiate, int),
1027 isInteger, isNumeric, isUnsignedInteger);
1028 1029 staticassert([Results] == [true, true, false]);
1030 }
1031 1032 /++
1033 ApplyLeft does a
1034 $(LINK2 http://en.wikipedia.org/wiki/Partial_application, partial application)
1035 of its arguments, providing a way to bind a set of arguments to the given
1036 template while delaying actually instantiating that template until the full
1037 set of arguments is provided. The "Left" in the name indicates that the
1038 initial arguments are one the left-hand side of the argument list
1039 when the given template is instantiated.
1040 1041 Essentially, ApplyLeft results in a template that stores Template and Args,
1042 and when that intermediate template is instantiated in turn, it instantiates
1043 Template with Args on the left-hand side of the arguments to Template and
1044 with the arguments to the intermediate template on the right-hand side -
1045 i.e. Args is applied to the left when instantiating Template.
1046 1047 So, if you have
1048 ---
1049 alias Intermediate = ApplyLeft!(MyTemplate, Arg1, Arg2);
1050 alias Result = Intermediate!(ArgA, ArgB);
1051 ---
1052 then that is equivalent to
1053 ---
1054 alias Result = MyTemplate!(Arg1, Arg2, ArgA, ArgB);
1055 ---
1056 with the difference being that you have an intermediate template which can
1057 be stored or passed to other templates (e.g. as a template predicate).
1058 1059 The only difference between ApplyLeft and $(LREF ApplyRight) is whether
1060 Args is on the left-hand or the right-hand side of the arguments given to
1061 Template when it's instantiated.
1062 1063 Note that in many cases, the need for ApplyLeft can be eliminated by making
1064 it so that Template can be partially instantiated. E.G.
1065 ---
1066 enum isSameType(T, U) = is(T == U);
1067 1068 template isSameType(T)
1069 {
1070 enum isSameType(U) = is(T == U);
1071 }
1072 ---
1073 makes it so that both of these work
1074 ---
1075 enum result1 = isSameType!(int, long);
1076 1077 alias Intermediate = isSameType!int;
1078 enum result2 = Intermediate!long;
1079 ---
1080 whereas if only the two argument version is provided, then ApplyLeft would
1081 be required for the second use case.
1082 ---
1083 enum result1 = isSameType!(int, long);
1084 1085 alias Intermediate = ApplyLeft!(isSameType, int);
1086 enum result2 = Intermediate!long;
1087 ---
1088 1089 See_Also:
1090 $(LREF ApplyRight)
1091 $(LREF Instantiate)
1092 +/1093 templateApplyLeft(aliasTemplate, Args...)
1094 {
1095 aliasApplyLeft(Right...) = Template!(Args, Right);
1096 }
1097 1098 ///1099 @safeunittest1100 {
1101 {
1102 aliasIntermediate = ApplyLeft!(AliasSeq, ubyte, ushort, uint);
1103 aliasResult = Intermediate!(char, wchar, dchar);
1104 staticassert(is(Result == AliasSeq!(ubyte, ushort, uint, char, wchar, dchar)));
1105 }
1106 {
1107 enumisImplicitlyConvertible(T, U) = is(T : U);
1108 1109 // i.e. isImplicitlyConvertible!(ubyte, T) is what all is checking for1110 // with each element in the AliasSeq.1111 staticassert(all!(ApplyLeft!(isImplicitlyConvertible, ubyte),
1112 short, ushort, int, uint, long, ulong));
1113 }
1114 {
1115 enumhasMember(T, stringmember) = __traits(hasMember, T, member);
1116 1117 structS1118 {
1119 boolfoo;
1120 intbar;
1121 stringbaz;
1122 }
1123 1124 staticassert(all!(ApplyLeft!(hasMember, S), "foo", "bar", "baz"));
1125 }
1126 {
1127 // Either set of arguments can be empty, since the first set is just1128 // stored to be applied later, and then when the intermediate template1129 // is instantiated, they're all applied to the given template in the1130 // requested order. However, whether the code compiles when1131 // instantiating the intermediate template depends on what kinds of1132 // arguments the given template requires.1133 1134 aliasIntermediate1 = ApplyLeft!AliasSeq;
1135 staticassert(Intermediate1!().length == 0);
1136 1137 enumisSameSize(T, U) = T.sizeof == U.sizeof;
1138 1139 aliasIntermediate2 = ApplyLeft!(isSameSize, int);
1140 staticassert(Intermediate2!uint);
1141 1142 aliasIntermediate3 = ApplyLeft!(isSameSize, int, uint);
1143 staticassert(Intermediate3!());
1144 1145 aliasIntermediate4 = ApplyLeft!(isSameSize);
1146 staticassert(Intermediate4!(int, uint));
1147 1148 // isSameSize requires two arguments1149 aliasIntermediate5 = ApplyLeft!isSameSize;
1150 staticassert(!__traits(compiles, Intermediate5!()));
1151 staticassert(!__traits(compiles, Intermediate5!int));
1152 staticassert(!__traits(compiles, Intermediate5!(int, long, string)));
1153 }
1154 }
1155 1156 /++
1157 ApplyRight does a
1158 $(LINK2 http://en.wikipedia.org/wiki/Partial_application, partial application)
1159 of its arguments, providing a way to bind a set of arguments to the given
1160 template while delaying actually instantiating that template until the full
1161 set of arguments is provided. The "Right" in the name indicates that the
1162 initial arguments are one the right-hand side of the argument list
1163 when the given template is instantiated.
1164 1165 Essentially, ApplyRight results in a template that stores Template and
1166 Args, and when that intermediate template is instantiated in turn, it
1167 instantiates Template with the arguments to the intermediate template on
1168 the left-hand side and with Args on the right-hand side - i.e. Args is
1169 applied to the right when instantiating Template.
1170 1171 So, if you have
1172 ---
1173 alias Intermediate = ApplyRight!(MyTemplate, Arg1, Arg2);
1174 alias Result = Intermediate!(ArgA, ArgB);
1175 ---
1176 then that is equivalent to
1177 ---
1178 alias Result = MyTemplate!(ArgA, ArgB, Arg1, Arg2);
1179 ---
1180 with the difference being that you have an intermediate template which can
1181 be stored or passed to other templates (e.g. as a template predicate).
1182 1183 The only difference between $(LREF ApplyLeft) and ApplyRight is whether
1184 Args is on the left-hand or the right-hand side of the arguments given to
1185 Template when it's instantiated.
1186 1187 See_Also:
1188 $(LREF ApplyLeft)
1189 $(LREF Instantiate)
1190 +/1191 templateApplyRight(aliasTemplate, Args...)
1192 {
1193 aliasApplyRight(Left...) = Template!(Left, Args);
1194 }
1195 1196 ///1197 @safeunittest1198 {
1199 {
1200 aliasIntermediate = ApplyRight!(AliasSeq, ubyte, ushort, uint);
1201 aliasResult = Intermediate!(char, wchar, dchar);
1202 staticassert(is(Result == AliasSeq!(char, wchar, dchar, ubyte, ushort, uint)));
1203 }
1204 {
1205 enumisImplicitlyConvertible(T, U) = is(T : U);
1206 1207 // i.e. isImplicitlyConvertible!(T, short) is what Filter is checking1208 // for with each element in the AliasSeq.1209 staticassert(is(Filter!(ApplyRight!(isImplicitlyConvertible, short),
1210 ubyte, string, short, float, int) ==
1211 AliasSeq!(ubyte, short)));
1212 }
1213 {
1214 enumhasMember(T, stringmember) = __traits(hasMember, T, member);
1215 1216 structS11217 {
1218 boolfoo;
1219 }
1220 1221 structS21222 {
1223 intfoo() { return42; }
1224 }
1225 1226 staticassert(all!(ApplyRight!(hasMember, "foo"), S1, S2));
1227 }
1228 {
1229 // Either set of arguments can be empty, since the first set is just1230 // stored to be applied later, and then when the intermediate template1231 // is instantiated, they're all applied to the given template in the1232 // requested order. However, whether the code compiles when1233 // instantiating the intermediate template depends on what kinds of1234 // arguments the given template requires.1235 1236 aliasIntermediate1 = ApplyRight!AliasSeq;
1237 staticassert(Intermediate1!().length == 0);
1238 1239 enumisSameSize(T, U) = T.sizeof == U.sizeof;
1240 1241 aliasIntermediate2 = ApplyRight!(isSameSize, int);
1242 staticassert(Intermediate2!uint);
1243 1244 aliasIntermediate3 = ApplyRight!(isSameSize, int, uint);
1245 staticassert(Intermediate3!());
1246 1247 aliasIntermediate4 = ApplyRight!(isSameSize);
1248 staticassert(Intermediate4!(int, uint));
1249 1250 // isSameSize requires two arguments1251 aliasIntermediate5 = ApplyRight!isSameSize;
1252 staticassert(!__traits(compiles, Intermediate5!()));
1253 staticassert(!__traits(compiles, Intermediate5!int));
1254 }
1255 }