1 // Written in the D programming language 2 /++ 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 module phobos.sys.meta; 96 97 // Example for converting types to values from module documentation. 98 @safe unittest 99 { 100 alias Types = AliasSeq!(int, byte, ulong, int[10]); 101 102 enum Sizeof(T) = T.sizeof; 103 104 alias sizesAsAliasSeq = Map!(Sizeof, Types); 105 static assert(sizesAsAliasSeq == AliasSeq!(4, 1, 8, 40)); 106 107 enum size_t[] sizes = [sizesAsAliasSeq]; 108 static assert(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 alias AliasSeq(TList...) = TList; 116 117 /// 118 @safe unittest 119 { 120 alias TL = AliasSeq!(int, double); 121 122 int foo(TL td) // same as int foo(int, double); 123 { 124 return td[0] + cast(int) td[1]; 125 } 126 } 127 128 /// 129 @safe unittest 130 { 131 alias TL = AliasSeq!(int, double); 132 133 alias Types = AliasSeq!(TL, char); 134 static assert(is(Types == AliasSeq!(int, double, char))); 135 } 136 137 /// 138 @safe unittest 139 { 140 static char foo(size_t i, string str) 141 { 142 return str[i]; 143 } 144 145 alias vars = 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 alias Alias(alias a) = a; 166 167 /// Ditto 168 alias Alias(T) = T; 169 170 /// 171 @safe unittest 172 { 173 // Without Alias this would fail if Args[0] were e.g. a value and 174 // some logic would be needed to detect when to use enum instead. 175 alias Head(Args...) = Alias!(Args[0]); 176 alias Tail(Args...) = Args[1 .. $]; 177 178 alias Blah = AliasSeq!(3, int, "hello"); 179 static assert(Head!Blah == 3); 180 static assert(is(Head!(Tail!Blah) == int)); 181 static assert((Tail!Blah)[1] == "hello"); 182 } 183 184 /// 185 @safe unittest 186 { 187 { 188 alias a = Alias!123; 189 static assert(a == 123); 190 } 191 { 192 enum e = 1; 193 alias a = Alias!e; 194 static assert(a == 1); 195 } 196 { 197 alias a = Alias!(3 + 4); 198 static assert(a == 7); 199 } 200 { 201 alias concat = (s0, s1) => s0 ~ s1; 202 alias a = Alias!(concat("Hello", " World!")); 203 static assert(a == "Hello World!"); 204 } 205 { 206 alias A = Alias!int; 207 static assert(is(A == int)); 208 } 209 { 210 alias A = Alias!(AliasSeq!int); 211 static assert(!is(typeof(A[0]))); // An Alias is not an AliasSeq. 212 static assert(is(A == int)); 213 } 214 { 215 auto i = 6; 216 alias a = 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 template Filter(alias Pred, Args...) 229 { 230 alias Filter = AliasSeq!(); 231 static foreach (Arg; Args) 232 { 233 static if (Pred!Arg) 234 Filter = AliasSeq!(Filter, Arg); 235 } 236 } 237 238 /// 239 @safe unittest 240 { 241 import phobos.sys.traits : isDynamicArray, isPointer, isUnsignedInteger; 242 243 alias Types = AliasSeq!(string, int, int[], bool[], ulong, double, ubyte); 244 245 static assert(is(Filter!(isDynamicArray, Types) == 246 AliasSeq!(string, int[], bool[]))); 247 248 static assert(is(Filter!(isUnsignedInteger, Types) == 249 AliasSeq!(ulong, ubyte))); 250 251 static assert(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 template Stride(int stepSize, Args...) 273 if (stepSize != 0) 274 { 275 alias Stride = AliasSeq!(); 276 static if (stepSize > 0) 277 { 278 static foreach (i; 0 .. (Args.length + stepSize - 1) / stepSize) 279 Stride = AliasSeq!(Stride, Args[i * stepSize]); 280 } 281 else 282 { 283 static foreach (i; 0 .. (Args.length - stepSize - 1) / -stepSize) 284 Stride = AliasSeq!(Stride, Args[$ - 1 + i * stepSize]); 285 } 286 } 287 288 /// 289 @safe unittest 290 { 291 static assert(is(Stride!(1, short, int, long) == AliasSeq!(short, int, long))); 292 static assert(is(Stride!(2, short, int, long) == AliasSeq!(short, long))); 293 static assert(is(Stride!(3, short, int, long) == AliasSeq!short)); 294 static assert(is(Stride!(100, short, int, long) == AliasSeq!short)); 295 296 static assert(is(Stride!(-1, short, int, long) == AliasSeq!(long, int, short))); 297 static assert(is(Stride!(-2, short, int, long) == AliasSeq!(long, short))); 298 static assert(is(Stride!(-3, short, int, long) == AliasSeq!long)); 299 static assert(is(Stride!(-100, short, int, long) == AliasSeq!long)); 300 301 alias Types = AliasSeq!(short, int, long, ushort, uint, ulong); 302 static assert(is(Stride!(3, Types) == AliasSeq!(short, ushort))); 303 static assert(is(Stride!(3, Types[1 .. $]) == AliasSeq!(int, uint))); 304 static assert(is(Stride!(-3, Types) == AliasSeq!(ulong, long))); 305 306 static assert(is(Stride!(-2, Types) == Stride!(2, Reverse!Types))); 307 308 static assert(is(Stride!1 == AliasSeq!())); 309 static assert(is(Stride!100 == AliasSeq!())); 310 } 311 312 @safe unittest 313 { 314 static assert(!__traits(compiles, Stride!(0, int))); 315 316 alias Types = AliasSeq!(bool, byte, ubyte, short, ushort, int, uint, long, ulong, 317 char, wchar, dchar, float, double, real, Object); 318 alias Types2 = AliasSeq!(bool, ubyte, ushort, uint, ulong, wchar, float, real); 319 alias Types3 = AliasSeq!(bool, short, uint, char, float, Object); 320 alias Types4 = AliasSeq!(bool, ushort, ulong, float); 321 alias Types5 = AliasSeq!(bool, int, wchar, Object); 322 alias Types6 = AliasSeq!(bool, uint, float); 323 alias Types7 = AliasSeq!(bool, long, real); 324 alias Types8 = AliasSeq!(bool, ulong); 325 alias Types9 = AliasSeq!(bool, char); 326 alias Types10 = AliasSeq!(bool, wchar); 327 328 static assert(is(Stride!(1, Types) == Types)); 329 static assert(is(Stride!(2, Types) == Types2)); 330 static assert(is(Stride!(3, Types) == Types3)); 331 static assert(is(Stride!(4, Types) == Types4)); 332 static assert(is(Stride!(5, Types) == Types5)); 333 static assert(is(Stride!(6, Types) == Types6)); 334 static assert(is(Stride!(7, Types) == Types7)); 335 static assert(is(Stride!(8, Types) == Types8)); 336 static assert(is(Stride!(9, Types) == Types9)); 337 static assert(is(Stride!(10, Types) == Types10)); 338 339 static assert(is(Stride!(-1, Types) == Reverse!Types)); 340 static assert(is(Stride!(-2, Types) == Stride!(2, Reverse!Types))); 341 static assert(is(Stride!(-3, Types) == Stride!(3, Reverse!Types))); 342 static assert(is(Stride!(-4, Types) == Stride!(4, Reverse!Types))); 343 static assert(is(Stride!(-5, Types) == Stride!(5, Reverse!Types))); 344 static assert(is(Stride!(-6, Types) == Stride!(6, Reverse!Types))); 345 static assert(is(Stride!(-7, Types) == Stride!(7, Reverse!Types))); 346 static assert(is(Stride!(-8, Types) == Stride!(8, Reverse!Types))); 347 static assert(is(Stride!(-9, Types) == Stride!(9, Reverse!Types))); 348 static assert(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 template Unique(alias Cmp, Args...) 373 { 374 alias Unique = AliasSeq!(); 375 static foreach (i, Arg; Args) 376 { 377 static if (i == 0) 378 Unique = AliasSeq!Arg; 379 else 380 Unique = AppendIfUnique!(Cmp, Unique, Arg); 381 } 382 } 383 384 // Unfortunately, this can't be done in-place in Unique, because then we get 385 // errors about reassigning Unique after reading it. 386 private template AppendIfUnique(alias Cmp, Args...) 387 { 388 static if (indexOf!(Cmp!(Args[$ - 1]), Args[0 .. $ - 1]) == -1) 389 alias AppendIfUnique = Args; 390 else 391 alias AppendIfUnique = Args[0 .. $ - 1]; 392 } 393 394 /// 395 @safe unittest 396 { 397 import phobos.sys.traits : isSameType; 398 399 alias Types1 = AliasSeq!(int, long, long, int, int, float, int); 400 401 static assert(is(Unique!(isSameType, Types1) == 402 AliasSeq!(int, long, float))); 403 404 alias Types2 = AliasSeq!(byte, ubyte, short, ushort, int, uint); 405 static assert(is(Unique!(isSameType, Types2) == Types2)); 406 407 // Empty AliasSeq. 408 static assert(Unique!isSameType.length == 0); 409 410 // An AliasSeq with a single element works as well. 411 static assert(Unique!(isSameType, int).length == 1); 412 } 413 414 /// 415 @safe unittest 416 { 417 import phobos.sys.traits : isSameSymbol; 418 419 int i; 420 string s; 421 real r; 422 alias Symbols = AliasSeq!(i, s, i, i, s, r, r, i); 423 424 alias Result = Unique!(isSameSymbol, Symbols); 425 static assert(Result.length == 3); 426 static assert(__traits(isSame, Result[0], i)); 427 static assert(__traits(isSame, Result[1], s)); 428 static assert(__traits(isSame, Result[2], r)); 429 430 // Comparing AliasSeqs for equality with is expressions only works 431 // if they only contain types. 432 static assert(!is(Symbols == Result)); 433 } 434 435 /// 436 @safe unittest 437 { 438 alias Types = AliasSeq!(int, uint, long, string, short, int*, ushort); 439 440 template sameSize(T) 441 { 442 enum sameSize(U) = T.sizeof == U.sizeof; 443 } 444 static assert(is(Unique!(sameSize, Types) == 445 AliasSeq!(int, long, string, short))); 446 447 // The predicate must be partially instantiable. 448 enum sameSize_fails(T, U) = T.sizeof == U.sizeof; 449 static assert(!__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 template Map(alias Fun, Args...) 460 { 461 alias Map = AliasSeq!(); 462 static foreach (Arg; Args) 463 Map = AliasSeq!(Map, Fun!Arg); 464 } 465 466 /// 467 @safe unittest 468 { 469 import phobos.sys.traits : Unqualified; 470 471 // empty 472 alias Empty = Map!Unqualified; 473 static assert(Empty.length == 0); 474 475 // single 476 alias Single = Map!(Unqualified, const int); 477 static assert(is(Single == AliasSeq!int)); 478 479 // several 480 alias Several = Map!(Unqualified, int, const int, immutable int, uint, 481 ubyte, byte, short, ushort, const long); 482 static assert(is(Several == AliasSeq!(int, int, int, uint, 483 ubyte, byte, short, ushort, long))); 484 485 alias ToDynamicArray(T) = T[]; 486 487 alias Arrays = Map!(ToDynamicArray, int, const ubyte, string); 488 static assert(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/8039 493 @safe unittest 494 { 495 template id(alias what) 496 { 497 enum id = __traits(identifier, what); 498 } 499 500 enum A { a } 501 static assert(Map!(id, A.a) == AliasSeq!"a"); 502 } 503 504 // regression test for https://issues.dlang.org/show_bug.cgi?id=21088 505 @system unittest // typeid opEquals is @system 506 { 507 enum getTypeId(T) = typeid(T); 508 alias A = 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 template Reverse(Args...) 518 { 519 alias Reverse = AliasSeq!(); 520 static foreach_reverse (Arg; Args) 521 Reverse = AliasSeq!(Reverse, Arg); 522 } 523 524 /// 525 @safe unittest 526 { 527 static assert(is(Reverse!(int, byte, long, string) == 528 AliasSeq!(string, long, byte, int))); 529 530 alias Types = AliasSeq!(int, long, long, int, float, 531 ubyte, short, ushort, uint); 532 static assert(is(Reverse!Types == AliasSeq!(uint, ushort, short, ubyte, 533 float, int, long, long, int))); 534 535 static assert(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) template all(alias Pred, Args...) 547 { 548 import core.internal.traits : allSatisfy; 549 alias all = allSatisfy!(Pred, Args); 550 } 551 else 552 { 553 import core.internal.traits : allSatisfy; 554 alias all = allSatisfy; 555 } 556 557 /// 558 @safe unittest 559 { 560 import phobos.sys.traits : isDynamicArray, isInteger; 561 562 static assert(!all!(isInteger, int, double)); 563 static assert( all!(isInteger, int, long)); 564 565 alias Types = AliasSeq!(string, int[], bool[]); 566 567 static assert( all!(isDynamicArray, Types)); 568 static assert(!all!(isInteger, Types)); 569 570 static assert( 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) template any(alias Pred, Args...) 582 { 583 import core.internal.traits : anySatisfy; 584 alias any = anySatisfy!(Pred, Args); 585 } 586 else 587 { 588 import core.internal.traits : anySatisfy; 589 alias any = anySatisfy; 590 } 591 592 /// 593 @safe unittest 594 { 595 import phobos.sys.traits : isDynamicArray, isInteger; 596 597 static assert(!any!(isInteger, string, double)); 598 static assert( any!(isInteger, int, double)); 599 600 alias Types = AliasSeq!(string, int[], bool[], real, bool); 601 602 static assert( any!(isDynamicArray, Types)); 603 static assert(!any!(isInteger, Types)); 604 605 static assert(!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 template indexOf(alias Pred, Args...) 620 { 621 enum ptrdiff_t indexOf = 622 { 623 static foreach (i; 0 .. Args.length) 624 { 625 static if (Pred!(Args[i])) 626 return i; 627 } 628 return -1; 629 }(); 630 } 631 632 /// 633 @safe unittest 634 { 635 import phobos.sys.traits : isInteger, isSameSymbol, isSameType; 636 637 alias Types1 = AliasSeq!(string, int, long, char[], ubyte, int); 638 alias Types2 = AliasSeq!(float, double, int[], char[], void); 639 640 static assert(indexOf!(isInteger, Types1) == 1); 641 static assert(indexOf!(isInteger, Types2) == -1); 642 643 static assert(indexOf!(isSameType!ubyte, Types1) == 4); 644 static assert(indexOf!(isSameType!ubyte, Types2) == -1); 645 646 int i; 647 int j; 648 string s; 649 int foo() { return 0; } 650 alias Symbols = AliasSeq!(i, j, foo); 651 static assert(indexOf!(isSameSymbol!j, Symbols) == 1); 652 static assert(indexOf!(isSameSymbol!s, Symbols) == -1); 653 654 // Empty AliasSeq. 655 static assert(indexOf!isInteger == -1); 656 657 // The predicate does not compile with all of the arguments, 658 // so indexOf does not compile. 659 static assert(!__traits(compiles, indexOf!(isSameType!int, long, int, 42))); 660 } 661 662 unittest 663 { 664 import phobos.sys.traits : isSameType; 665 666 static assert(indexOf!(isSameType!int, short, int, long) >= 0); 667 static assert(indexOf!(isSameType!string, short, int, long) < 0); 668 669 // This is to verify that we don't accidentally end up with the type of 670 // the result differing based on whether it's -1 or not. Not specifying the 671 // type at all in indexOf results in -1 being int on all systems and the 672 // other results being whatever size_t is (ulong on most systems at this 673 // point), which does generally work, but being explicit with the type 674 // avoids any subtle issues that might come from the type of the result 675 // varying based on whether the item is found or not. 676 static assert(is(typeof(indexOf!(isSameType!int, short, int, long)) == 677 typeof(indexOf!(isSameType!string, short, int, long)))); 678 679 static assert(indexOf!(isSameType!string, string, string, string, string) == 0); 680 static assert(indexOf!(isSameType!string, int, string, string, string) == 1); 681 static assert(indexOf!(isSameType!string, int, int, string, string) == 2); 682 static assert(indexOf!(isSameType!string, int, int, int, string) == 3); 683 static assert(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 template And(Preds...) 701 { 702 enum And(Args...) = 703 { 704 static foreach (Pred; Preds) 705 { 706 static if (!Pred!Args) 707 return false; 708 } 709 return true; 710 }(); 711 } 712 713 /// 714 @safe unittest 715 { 716 import phobos.sys.traits : isNumeric; 717 718 template isSameSize(size_t size) 719 { 720 enum isSameSize(T) = T.sizeof == size; 721 } 722 723 alias is32BitNumeric = And!(isNumeric, isSameSize!4); 724 725 static assert(!is32BitNumeric!short); 726 static assert( is32BitNumeric!int); 727 static assert(!is32BitNumeric!long); 728 static assert( is32BitNumeric!float); 729 static assert(!is32BitNumeric!double); 730 static assert(!is32BitNumeric!(int*)); 731 732 // An empty sequence of predicates always yields true. 733 alias alwaysTrue = And!(); 734 static assert(alwaysTrue!int); 735 } 736 737 /++ 738 Predicates with multiple parameters are also supported. However, the number 739 of parameters must match. 740 +/ 741 @safe unittest 742 { 743 import phobos.sys.traits : isImplicitlyConvertible, isInteger, isSameType; 744 745 alias isOnlyImplicitlyConvertible 746 = And!(Not!isSameType, isImplicitlyConvertible); 747 748 static assert( isOnlyImplicitlyConvertible!(int, long)); 749 static assert(!isOnlyImplicitlyConvertible!(int, int)); 750 static assert(!isOnlyImplicitlyConvertible!(long, int)); 751 752 static assert( isOnlyImplicitlyConvertible!(string, const(char)[])); 753 static assert(!isOnlyImplicitlyConvertible!(string, string)); 754 static assert(!isOnlyImplicitlyConvertible!(const(char)[], string)); 755 756 // Mismatched numbers of parameters. 757 alias doesNotWork = And!(isInteger, isImplicitlyConvertible); 758 static assert(!__traits(compiles, doesNotWork!int)); 759 static assert(!__traits(compiles, doesNotWork!(int, long))); 760 } 761 762 @safe unittest 763 { 764 enum testAlways(Args...) = true; 765 enum testNever(Args...) = false; 766 767 static assert( Instantiate!(And!(testAlways, testAlways, testAlways), int)); 768 static assert(!Instantiate!(And!(testAlways, testAlways, testNever), int)); 769 static assert(!Instantiate!(And!(testAlways, testNever, testNever), int)); 770 static assert(!Instantiate!(And!(testNever, testNever, testNever), int)); 771 static assert(!Instantiate!(And!(testNever, testNever, testAlways), int)); 772 static assert(!Instantiate!(And!(testNever, testAlways, testAlways), int)); 773 774 static assert( Instantiate!(And!(testAlways, testAlways), int)); 775 static assert(!Instantiate!(And!(testAlways, testNever), int)); 776 static assert(!Instantiate!(And!(testNever, testAlways), int)); 777 static assert(!Instantiate!(And!(testNever, testNever), int)); 778 779 static assert( Instantiate!(And!testAlways, int)); 780 static assert(!Instantiate!(And!testNever, int)); 781 782 // No short-circuiting. 783 import phobos.sys.traits : isEqual, isFloatingPoint; 784 static assert(!Instantiate!(And!isFloatingPoint, int)); 785 static assert(!__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 template Not(alias Pred) 796 { 797 enum Not(Args...) = !Pred!Args; 798 } 799 800 /// 801 @safe unittest 802 { 803 import phobos.sys.traits : isDynamicArray, isPointer; 804 805 alias isNotPointer = Not!isPointer; 806 static assert( isNotPointer!int); 807 static assert(!isNotPointer!(int*)); 808 static assert( all!(isNotPointer, string, char, float)); 809 810 static assert(!all!(Not!isDynamicArray, string, char[], int[], long)); 811 static assert( any!(Not!isDynamicArray, string, char[], int[], long)); 812 } 813 814 /++ 815 Predicates with multiple parameters are also supported. 816 +/ 817 @safe unittest 818 { 819 import phobos.sys.traits : isImplicitlyConvertible, isInteger; 820 821 alias notImplicitlyConvertible = Not!isImplicitlyConvertible; 822 823 static assert( notImplicitlyConvertible!(long, int)); 824 static assert(!notImplicitlyConvertible!(int, long)); 825 826 static assert( notImplicitlyConvertible!(const(char)[], string)); 827 static assert(!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 template Or(Preds...) 845 { 846 enum Or(Args...) = 847 { 848 static foreach (Pred; Preds) 849 { 850 static if (Pred!Args) 851 return true; 852 } 853 return false; 854 }(); 855 } 856 857 /// 858 @safe unittest 859 { 860 import phobos.sys.traits : isFloatingPoint, isSignedInteger; 861 862 alias isSignedNumeric = Or!(isFloatingPoint, isSignedInteger); 863 864 static assert( isSignedNumeric!short); 865 static assert( isSignedNumeric!long); 866 static assert( isSignedNumeric!double); 867 static assert(!isSignedNumeric!uint); 868 static assert(!isSignedNumeric!ulong); 869 static assert(!isSignedNumeric!string); 870 static assert(!isSignedNumeric!(int*)); 871 872 // An empty sequence of predicates always yields false. 873 alias alwaysFalse = Or!(); 874 static assert(!alwaysFalse!int); 875 } 876 877 /++ 878 Predicates with multiple parameters are also supported. However, the number 879 of parameters must match. 880 +/ 881 @safe unittest 882 { 883 import phobos.sys.traits : isImplicitlyConvertible, isInteger; 884 885 enum isSameSize(T, U) = T.sizeof == U.sizeof; 886 alias convertibleOrSameSize = Or!(isImplicitlyConvertible, isSameSize); 887 888 static assert( convertibleOrSameSize!(int, int)); 889 static assert( convertibleOrSameSize!(int, long)); 890 static assert(!convertibleOrSameSize!(long, int)); 891 892 static assert( convertibleOrSameSize!(int, float)); 893 static assert( convertibleOrSameSize!(float, int)); 894 static assert(!convertibleOrSameSize!(double, int)); 895 static assert(!convertibleOrSameSize!(float, long)); 896 897 static assert( convertibleOrSameSize!(int*, string*)); 898 899 // Mismatched numbers of parameters. 900 alias doesNotWork = Or!(isInteger, isImplicitlyConvertible); 901 static assert(!__traits(compiles, doesNotWork!int)); 902 static assert(!__traits(compiles, doesNotWork!(int, long))); 903 } 904 905 @safe unittest 906 { 907 enum testAlways(Args...) = true; 908 enum testNever(Args...) = false; 909 910 static assert( Instantiate!(Or!(testAlways, testAlways, testAlways), int)); 911 static assert( Instantiate!(Or!(testAlways, testAlways, testNever), int)); 912 static assert( Instantiate!(Or!(testAlways, testNever, testNever), int)); 913 static assert(!Instantiate!(Or!(testNever, testNever, testNever), int)); 914 915 static assert( Instantiate!(Or!(testAlways, testAlways), int)); 916 static assert( Instantiate!(Or!(testAlways, testNever), int)); 917 static assert( Instantiate!(Or!(testNever, testAlways), int)); 918 static assert(!Instantiate!(Or!(testNever, testNever), int)); 919 920 static assert( Instantiate!(Or!testAlways, int)); 921 static assert(!Instantiate!(Or!testNever, int)); 922 923 static assert(Instantiate!(Or!testAlways, int)); 924 static assert(Instantiate!(Or!testAlways, Map)); 925 static assert(Instantiate!(Or!testAlways, int, Map)); 926 927 // No short-circuiting. 928 import phobos.sys.traits : isEqual, isInteger; 929 static assert( Instantiate!(Or!isInteger, int)); 930 static assert(!__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 alias Instantiate(alias Template, Args...) = Template!Args; 972 973 /// 974 @safe unittest 975 { 976 import phobos.sys.traits : ConstOf, isImplicitlyConvertible, isSameType, isInteger; 977 978 alias Templates = 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 static assert( Instantiate!(Templates[0], long)); 986 static assert(!Instantiate!(Templates[0], string)); 987 988 static assert(!Instantiate!(Templates[1], long)); 989 static assert( Instantiate!(Templates[1], string)); 990 991 static assert( Instantiate!(Templates[2], long)); 992 static assert(!Instantiate!(Templates[2], string)); 993 994 static assert(is(Instantiate!(Templates[3], int) == const int)); 995 static assert(is(Instantiate!(Templates[3], double) == const double)); 996 } 997 998 /// 999 @safe unittest 1000 { 1001 template hasMember(string member) 1002 { 1003 enum hasMember(T) = __traits(hasMember, T, member); 1004 } 1005 1006 struct S 1007 { 1008 int foo; 1009 } 1010 1011 // hasMember!"foo"!S does not compile, 1012 // because having multiple ! arguments is not allowed. 1013 1014 static assert( Instantiate!(hasMember!"foo", S)); 1015 static assert(!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 @safe unittest 1023 { 1024 import phobos.sys.traits : isInteger, isNumeric, isUnsignedInteger; 1025 1026 alias Results = Map!(ApplyRight!(Instantiate, int), 1027 isInteger, isNumeric, isUnsignedInteger); 1028 1029 static assert([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 template ApplyLeft(alias Template, Args...) 1094 { 1095 alias ApplyLeft(Right...) = Template!(Args, Right); 1096 } 1097 1098 /// 1099 @safe unittest 1100 { 1101 { 1102 alias Intermediate = ApplyLeft!(AliasSeq, ubyte, ushort, uint); 1103 alias Result = Intermediate!(char, wchar, dchar); 1104 static assert(is(Result == AliasSeq!(ubyte, ushort, uint, char, wchar, dchar))); 1105 } 1106 { 1107 enum isImplicitlyConvertible(T, U) = is(T : U); 1108 1109 // i.e. isImplicitlyConvertible!(ubyte, T) is what all is checking for 1110 // with each element in the AliasSeq. 1111 static assert(all!(ApplyLeft!(isImplicitlyConvertible, ubyte), 1112 short, ushort, int, uint, long, ulong)); 1113 } 1114 { 1115 enum hasMember(T, string member) = __traits(hasMember, T, member); 1116 1117 struct S 1118 { 1119 bool foo; 1120 int bar; 1121 string baz; 1122 } 1123 1124 static assert(all!(ApplyLeft!(hasMember, S), "foo", "bar", "baz")); 1125 } 1126 { 1127 // Either set of arguments can be empty, since the first set is just 1128 // stored to be applied later, and then when the intermediate template 1129 // is instantiated, they're all applied to the given template in the 1130 // requested order. However, whether the code compiles when 1131 // instantiating the intermediate template depends on what kinds of 1132 // arguments the given template requires. 1133 1134 alias Intermediate1 = ApplyLeft!AliasSeq; 1135 static assert(Intermediate1!().length == 0); 1136 1137 enum isSameSize(T, U) = T.sizeof == U.sizeof; 1138 1139 alias Intermediate2 = ApplyLeft!(isSameSize, int); 1140 static assert(Intermediate2!uint); 1141 1142 alias Intermediate3 = ApplyLeft!(isSameSize, int, uint); 1143 static assert(Intermediate3!()); 1144 1145 alias Intermediate4 = ApplyLeft!(isSameSize); 1146 static assert(Intermediate4!(int, uint)); 1147 1148 // isSameSize requires two arguments 1149 alias Intermediate5 = ApplyLeft!isSameSize; 1150 static assert(!__traits(compiles, Intermediate5!())); 1151 static assert(!__traits(compiles, Intermediate5!int)); 1152 static assert(!__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 template ApplyRight(alias Template, Args...) 1192 { 1193 alias ApplyRight(Left...) = Template!(Left, Args); 1194 } 1195 1196 /// 1197 @safe unittest 1198 { 1199 { 1200 alias Intermediate = ApplyRight!(AliasSeq, ubyte, ushort, uint); 1201 alias Result = Intermediate!(char, wchar, dchar); 1202 static assert(is(Result == AliasSeq!(char, wchar, dchar, ubyte, ushort, uint))); 1203 } 1204 { 1205 enum isImplicitlyConvertible(T, U) = is(T : U); 1206 1207 // i.e. isImplicitlyConvertible!(T, short) is what Filter is checking 1208 // for with each element in the AliasSeq. 1209 static assert(is(Filter!(ApplyRight!(isImplicitlyConvertible, short), 1210 ubyte, string, short, float, int) == 1211 AliasSeq!(ubyte, short))); 1212 } 1213 { 1214 enum hasMember(T, string member) = __traits(hasMember, T, member); 1215 1216 struct S1 1217 { 1218 bool foo; 1219 } 1220 1221 struct S2 1222 { 1223 int foo() { return 42; } 1224 } 1225 1226 static assert(all!(ApplyRight!(hasMember, "foo"), S1, S2)); 1227 } 1228 { 1229 // Either set of arguments can be empty, since the first set is just 1230 // stored to be applied later, and then when the intermediate template 1231 // is instantiated, they're all applied to the given template in the 1232 // requested order. However, whether the code compiles when 1233 // instantiating the intermediate template depends on what kinds of 1234 // arguments the given template requires. 1235 1236 alias Intermediate1 = ApplyRight!AliasSeq; 1237 static assert(Intermediate1!().length == 0); 1238 1239 enum isSameSize(T, U) = T.sizeof == U.sizeof; 1240 1241 alias Intermediate2 = ApplyRight!(isSameSize, int); 1242 static assert(Intermediate2!uint); 1243 1244 alias Intermediate3 = ApplyRight!(isSameSize, int, uint); 1245 static assert(Intermediate3!()); 1246 1247 alias Intermediate4 = ApplyRight!(isSameSize); 1248 static assert(Intermediate4!(int, uint)); 1249 1250 // isSameSize requires two arguments 1251 alias Intermediate5 = ApplyRight!isSameSize; 1252 static assert(!__traits(compiles, Intermediate5!())); 1253 static assert(!__traits(compiles, Intermediate5!int)); 1254 } 1255 }