1 module it.cpp.templates; 2 3 import it; 4 5 @("simple") 6 @safe unittest { 7 shouldCompile( 8 Cpp( 9 q{ 10 template<typename T> 11 struct vector { 12 public: 13 T value; 14 void push_back(); 15 }; 16 17 template<typename U, int length> 18 struct array { 19 public: 20 U elements[length]; 21 }; 22 23 } 24 ), 25 D( 26 q{ 27 auto vi = vector!int(42); 28 static assert(is(typeof(vi.value) == int)); 29 vi.value = 33; 30 31 auto vf = vector!float(33.3); 32 static assert(is(typeof(vf.value) == float)); 33 vf.value = 22.2; 34 35 auto vs = vector!string("foo"); 36 static assert(is(typeof(vs.value) == string)); 37 vs.value = "bar"; 38 39 auto ai = array!(int, 3)(); 40 static assert(ai.elements.length == 3); 41 static assert(is(typeof(ai.elements[0]) == int)); 42 } 43 ), 44 ); 45 } 46 47 @("template nameless type") 48 @safe unittest { 49 shouldCompile( 50 Cpp( 51 q{ 52 // none of the template parameters have names, which is allowed 53 // in C++ but not in D 54 template<bool, bool, typename> 55 struct Foo { 56 57 }; 58 } 59 ), 60 D( 61 q{ 62 auto f = Foo!(true, false, int)(); 63 } 64 ), 65 ); 66 } 67 68 @("struct full specialisation") 69 @safe unittest { 70 shouldCompile( 71 Cpp( 72 q{ 73 // this is a ClassTemplate 74 template<bool, bool, typename> 75 struct __copy_move { 76 enum { value = 42 }; 77 }; 78 79 // This is a StructDecl 80 template<> 81 struct __copy_move<false, true, double> { 82 enum { value = 33 }; 83 }; 84 } 85 ), 86 D( 87 q{ 88 import std.conv: text; 89 90 // FIXME: libclang bug - templates don't have proper 91 // EnumConstantDecl values for some reason 92 // auto c1 = __copy_move!(true, true, int)(); 93 // static assert(c1.value == 42, text(cast(int) c1.value)); 94 95 auto c2 = __copy_move!(false, true, double)(); 96 static assert(c2.value == 33, text(cast(int) c2.value)); 97 } 98 ), 99 ); 100 } 101 102 // struct/class keyword could end up in different code paths 103 @("class full specialisation") 104 @safe unittest { 105 shouldCompile( 106 Cpp( 107 q{ 108 // this is a ClassTemplate 109 template<bool, bool, typename> 110 class __copy_move { 111 public: 112 enum { value = 42 }; 113 }; 114 115 // This is a ClassDecl 116 template<> 117 class __copy_move<false, true, double> { 118 public: 119 enum { value = 33 }; 120 }; 121 } 122 ), 123 D( 124 q{ 125 import std.conv: text; 126 127 // FIXME: libclang bug - templates don't have proper 128 // EnumConstantDecl values for some reason 129 // auto c1 = __copy_move!(true, true, int)(); 130 // static assert(c1.value == 42, text(cast(int) c1.value)); 131 132 auto c2 = __copy_move!(false, true, double)(); 133 static assert(c2.value == 33, text(cast(int) c2.value)); 134 } 135 ), 136 ); 137 } 138 139 @("struct partial specialisation") 140 @safe unittest { 141 shouldCompile( 142 Cpp( 143 q{ 144 // just structs to use as template type parameters 145 struct Foo; struct Bar; struct Baz; struct Quux; 146 147 // this is a ClassTemplate 148 template<typename, typename, bool, typename, int, typename> 149 struct Template { using Type = bool; }; 150 151 // this is a ClassTemplatePartialSpecialization 152 template<typename T, bool V0, typename T3, typename T4> 153 struct Template<Quux, T, V0, T3, 42, T4> { using Type = short; }; 154 155 // this is a ClassTemplatePartialSpecialization 156 template<typename T, bool V0, typename T3, typename T4> 157 struct Template<T, Quux, V0, T3, 42, T4> { using Type = double; }; 158 } 159 ), 160 D( 161 q{ 162 import std.conv: text; 163 164 auto t1 = Template!(Foo, Bar, false, Baz, 0, Quux)(); // full template 165 auto t2 = Template!(Quux, Bar, false, Baz, 42, Quux)(); // partial1 166 auto t3 = Template!(Foo, Quux, false, Baz, 42, Quux)(); // partial2 167 168 static assert(is(t1.Type == bool), t2.Type.stringof); 169 static assert(is(t2.Type == short), t2.Type.stringof); 170 static assert(is(t3.Type == double), t3.Type.stringof); 171 } 172 ), 173 ); 174 } 175 176 177 178 // as seen in stl_algobase.h 179 @("__copy_move") 180 @safe unittest { 181 shouldCompile( 182 Cpp( 183 q{ 184 namespace std { 185 struct random_access_iterator_tag; 186 187 template<bool, bool, typename> 188 struct __copy_move {}; 189 190 template<typename _Category> 191 struct __copy_move<true, false, _Category> {}; 192 193 template<> 194 struct __copy_move<false, false, random_access_iterator_tag> {}; 195 196 template<> 197 struct __copy_move<true, false, random_access_iterator_tag> {}; 198 199 template<bool _IsMove> 200 struct __copy_move<_IsMove, true, random_access_iterator_tag> {}; 201 } 202 } 203 ), 204 D( 205 q{ 206 struct RandomStruct {} 207 auto c1 = __copy_move!(false, true, int)(); 208 auto c2 = __copy_move!(true, false, RandomStruct)(); 209 auto c3 = __copy_move!(false, false, random_access_iterator_tag)(); 210 auto c4 = __copy_move!(true, false, random_access_iterator_tag)(); 211 auto c5 = __copy_move!(false, true, random_access_iterator_tag)(); 212 auto c6 = __copy_move!(true, true, random_access_iterator_tag)(); 213 } 214 ), 215 ); 216 } 217 218 219 @("constexpr struct variable") 220 @safe unittest { 221 shouldCompile( 222 Cpp( 223 q{ 224 template<typename _Tp, _Tp __v> 225 struct integral_constant { 226 public: // FIXME #76 227 static constexpr _Tp value = __v; 228 }; 229 } 230 ), 231 D( 232 q{ 233 static assert(integral_constant!(int, 42).value == 42); 234 static assert(integral_constant!(int, 33).value == 33); 235 } 236 ), 237 ); 238 } 239 240 @("typedef to template type parameter") 241 @safe unittest { 242 shouldCompile( 243 Cpp( 244 q{ 245 template<typename _Tp, _Tp __v> 246 struct integral_constant { 247 public: // FIXME #76 248 typedef _Tp value_type; 249 }; 250 } 251 ), 252 D( 253 q{ 254 static assert(is(integral_constant!(short, 42).value_type == short)); 255 static assert(is(integral_constant!(long, 42).value_type == long)); 256 } 257 ), 258 ); 259 } 260 261 @("typedef to template struct") 262 @safe unittest { 263 shouldCompile( 264 Cpp( 265 q{ 266 template<typename _Tp, _Tp __v> 267 struct integral_constant { 268 public: // FIXME #76 269 typedef integral_constant<_Tp, __v> type; 270 }; 271 } 272 ), 273 D( 274 q{ 275 static assert(is(integral_constant!(int, 33).type == integral_constant!(int, 33))); 276 } 277 ), 278 ); 279 } 280 281 @("opCast template type") 282 @safe unittest { 283 shouldCompile( 284 Cpp( 285 q{ 286 template<typename _Tp, _Tp __v> 287 struct integral_constant 288 { 289 public: // FIXME #76 290 static constexpr _Tp value = __v; 291 typedef _Tp value_type; 292 constexpr operator value_type() const noexcept { return value; } 293 }; 294 } 295 ), 296 D( 297 q{ 298 integral_constant!(int , 42) i; 299 auto j = cast(int) i; 300 } 301 ), 302 ); 303 } 304 305 306 // as seen in type_traits 307 @("integral_constant") 308 @safe unittest { 309 shouldCompile( 310 Cpp( 311 q{ 312 template<typename _Tp, _Tp __v> 313 struct integral_constant 314 { 315 public: // FIXME #76 316 static constexpr _Tp value = __v; 317 typedef _Tp value_type; 318 constexpr operator value_type() const noexcept { return value; } 319 constexpr value_type operator()() const noexcept { return value; } 320 }; 321 } 322 ), 323 D( 324 q{ 325 } 326 ), 327 ); 328 } 329 330 331 @("variadic.base.types") 332 @safe unittest { 333 shouldCompile( 334 Cpp( 335 q{ 336 template<int, typename, bool, typename...> 337 struct VariadicTypes { 338 using Type = void; 339 }; 340 } 341 ), 342 D( 343 q{ 344 static assert(is(VariadicTypes!(0, short, false).Type == void)); 345 static assert(is(VariadicTypes!(1, short, false, int).Type == void)); 346 static assert(is(VariadicTypes!(2, short, false, int, double, bool).Type == void)); 347 static assert(is(VariadicTypes!(3, short, false, int, int).Type == void)); 348 } 349 ), 350 ); 351 } 352 353 @("variadic.base.values") 354 @safe unittest { 355 shouldCompile( 356 Cpp( 357 q{ 358 template<short, typename, bool, int...> 359 struct VariadicValues { 360 using Type = void; 361 }; 362 } 363 ), 364 D( 365 q{ 366 static assert(is(VariadicValues!(0, float, false).Type == void)); 367 static assert(is(VariadicValues!(1, float, false, 0, 1, 2, 3).Type == void)); 368 } 369 ), 370 ); 371 } 372 373 374 375 @("variadic.specialized") 376 @safe unittest { 377 shouldCompile( 378 Cpp( 379 q{ 380 template<typename...> 381 struct Variadic { 382 using Type = void; 383 }; 384 385 template<typename T0, typename T1> 386 struct Variadic<T0, T1> { 387 using Type = bool; 388 }; 389 } 390 ), 391 D( 392 q{ 393 static assert(is(Variadic!().Type == void)); // general 394 static assert(is(Variadic!(int).Type == void)); // general 395 static assert(is(Variadic!(int, double, bool).Type == void)); // general 396 static assert(is(Variadic!(int, int).Type == bool)); // specialisation 397 } 398 ), 399 ); 400 } 401 402 403 // as seen in type_traits 404 @("__or_") 405 @safe unittest { 406 shouldCompile( 407 Cpp( 408 q{ 409 template<typename _Tp, _Tp __v> 410 struct integral_constant 411 { 412 static constexpr _Tp value = __v; 413 typedef _Tp value_type; 414 typedef integral_constant<_Tp, __v> type; 415 constexpr operator value_type() const noexcept { return value; } 416 constexpr value_type operator()() const noexcept { return value; } 417 }; 418 419 template<typename _Tp, _Tp __v> 420 constexpr _Tp integral_constant<_Tp, __v>::value; 421 422 typedef integral_constant<bool, true> true_type; 423 424 typedef integral_constant<bool, false> false_type; 425 426 template<bool, typename, typename> 427 struct conditional; 428 429 template<typename...> 430 struct __or_; 431 432 template<> 433 struct __or_<> : public false_type { }; 434 435 template<typename _B1> 436 struct __or_<_B1> : public _B1 { }; 437 438 template<typename _B1, typename _B2> 439 struct __or_<_B1, _B2> 440 : public conditional<_B1::value, _B1, _B2>::type 441 { }; 442 443 template<typename _B1, typename _B2, typename _B3, typename... _Bn> 444 struct __or_<_B1, _B2, _B3, _Bn...> 445 : public conditional<_B1::value, _B1, __or_<_B2, _B3, _Bn...>>::type 446 { }; 447 448 template<bool _Cond, typename _Iftrue, typename _Iffalse> 449 struct conditional 450 { typedef _Iftrue type; }; 451 452 template<typename _Iftrue, typename _Iffalse> 453 struct conditional<false, _Iftrue, _Iffalse> 454 { typedef _Iffalse type; }; 455 } 456 ), 457 D( 458 q{ 459 } 460 ), 461 ); 462 } 463 464 465 // as seen in type traits 466 @("is_lvalue_reference") 467 @safe unittest { 468 shouldCompile( 469 Cpp( 470 q{ 471 template<typename _Tp, _Tp __v> 472 struct integral_constant 473 { 474 static constexpr _Tp value = __v; 475 typedef _Tp value_type; 476 typedef integral_constant<_Tp, __v> type; 477 constexpr operator value_type() const noexcept { return value; } 478 constexpr value_type operator()() const noexcept { return value; } 479 }; 480 481 template<typename _Tp, _Tp __v> 482 constexpr _Tp integral_constant<_Tp, __v>::value; 483 484 typedef integral_constant<bool, true> true_type; 485 typedef integral_constant<bool, false> false_type; 486 487 template<typename> 488 struct is_lvalue_reference: public false_type { }; 489 490 template<typename _Tp> 491 struct is_lvalue_reference<_Tp&>: public true_type { }; 492 } 493 ), 494 D( 495 q{ 496 // FIXME #85 497 // static assert(!is_lvalue_reference!int.value); 498 // static assert( is_lvalue_reference!(int*).value); 499 } 500 ), 501 ); 502 } 503 504 505 // as seen in type traits 506 @("decltype") 507 @safe unittest { 508 shouldCompile( 509 Cpp( 510 q{ 511 template<typename T> 512 struct Struct { 513 T i; 514 using Type = decltype(i); 515 }; 516 } 517 ), 518 D( 519 q{ 520 static assert(is(Struct!int.Type == int)); 521 static assert(is(Struct!double.Type == double)); 522 } 523 ), 524 ); 525 } 526 527 528 // as seen in type traits 529 @("typename") 530 @safe unittest { 531 shouldCompile( 532 Cpp( 533 q{ 534 template<typename T> 535 struct TheType { 536 using Type = T; 537 }; 538 539 template<typename T> 540 struct Struct { 541 using AlsoType = typename TheType<T>::Type; 542 }; 543 } 544 ), 545 D( 546 q{ 547 static assert(is(Struct!int.AlsoType == int)); 548 static assert(is(Struct!double.AlsoType == double)); 549 } 550 ), 551 ); 552 } 553 554 555 // as seen in type traits 556 @("add_volatile") 557 @safe unittest { 558 shouldCompile( 559 Cpp( 560 q{ 561 template<typename T> 562 struct add_volatile { using Type = volatile T; }; 563 } 564 ), 565 D( 566 q{ 567 static assert(is(add_volatile!int.Type == int)); 568 static assert(is(add_volatile!double.Type == double)); 569 } 570 ), 571 ); 572 } 573 574 575 // as seen in type traits 576 @("unsigned") 577 @safe unittest { 578 shouldCompile( 579 Cpp( 580 q{ 581 template<bool C, typename T0, typename T1> 582 struct Helper { 583 using Type = T1; 584 }; 585 586 template<typename T> 587 struct Thingie { 588 static const bool b0 = sizeof(T) < sizeof(unsigned short); 589 using Type = typename Helper<b0, unsigned long, unsigned long long>::Type; 590 }; 591 } 592 ), 593 D( 594 q{ 595 } 596 ), 597 ); 598 } 599 600 601 @("sizeof") 602 @safe unittest { 603 shouldCompile( 604 Cpp( 605 q{ 606 template<typename T> 607 struct Thingie { 608 static constexpr auto b0 = sizeof(T) < sizeof(unsigned short); 609 }; 610 } 611 ), 612 D( 613 q{ 614 static assert( Thingie!ubyte.b0); 615 static assert(!Thingie!int.b0); 616 } 617 ), 618 ); 619 }