1 module it.cpp.class_; 2 3 import it; 4 5 @("POD struct") 6 @safe unittest { 7 shouldCompile( 8 Cpp( 9 q{ 10 struct Foo { int i; double d; }; 11 } 12 ), 13 D( 14 q{ 15 auto f = Foo(42, 33.3); 16 static assert(is(Foo == struct), "Foo should be a struct"); 17 f.i = 7; 18 f.d = 3.14; 19 } 20 ), 21 ); 22 } 23 24 @("POD struct private then public") 25 @safe unittest { 26 shouldCompile( 27 Cpp( 28 q{ 29 struct Foo { 30 private: 31 int i; 32 public: 33 double d; 34 }; 35 } 36 ), 37 D( 38 q{ 39 static assert(is(Foo == struct), "Foo should be a struct"); 40 static assert(__traits(getProtection, __traits(getMember, Foo, "i")) == "private"); 41 static assert(__traits(getProtection, __traits(getMember, Foo, "d")) == "public"); 42 Foo f; 43 f.d = 22.2; 44 } 45 ), 46 ); 47 } 48 49 50 @("POD class") 51 @safe unittest { 52 shouldCompile( 53 Cpp( 54 q{ 55 class Foo { int i; double d; }; 56 } 57 ), 58 D( 59 q{ 60 static assert(is(Foo == struct), "Foo should be a struct"); 61 static assert(__traits(getProtection, __traits(getMember, Foo, "i")) == "private"); 62 static assert(__traits(getProtection, __traits(getMember, Foo, "d")) == "private"); 63 } 64 ), 65 ); 66 } 67 68 @("POD class public then private") 69 @safe unittest { 70 shouldCompile( 71 Cpp( 72 q{ 73 class Foo { 74 public: 75 int i; 76 private: 77 double d; 78 }; 79 } 80 ), 81 D( 82 q{ 83 static assert(is(Foo == struct), "Foo should be a struct"); 84 static assert(__traits(getProtection, __traits(getMember, Foo, "i")) == "public"); 85 static assert(__traits(getProtection, __traits(getMember, Foo, "d")) == "private"); 86 Foo f; 87 f.i = 7; // public, ok 88 } 89 ), 90 ); 91 } 92 93 94 @("struct method") 95 @safe unittest { 96 shouldCompile( 97 Cpp( 98 q{ 99 struct Adder { 100 int add(int i, int j); 101 }; 102 } 103 ), 104 D( 105 q{ 106 static assert(is(Adder == struct), "Adder should be a struct"); 107 auto adder = Adder(); 108 int i = adder.add(2, 3); 109 } 110 ), 111 ); 112 } 113 114 @("ctor") 115 @safe unittest { 116 shouldCompile( 117 Cpp( 118 q{ 119 struct Adder { 120 int i; 121 Adder(int i, int j); 122 int add(int j); 123 }; 124 } 125 ), 126 D( 127 q{ 128 static assert(is(Adder == struct), "Adder should be a struct"); 129 auto adder = Adder(1, 2); 130 int i = adder.add(4); 131 } 132 ), 133 ); 134 } 135 136 @("const method") 137 @safe unittest { 138 shouldCompile( 139 Cpp( 140 q{ 141 struct Adder { 142 int i; 143 Adder(int i, int j); 144 int add(int j) const; 145 }; 146 } 147 ), 148 D( 149 q{ 150 static assert(is(Adder == struct), "Adder should be a struct"); 151 auto adder = const Adder(1, 2); 152 int i = adder.add(4); 153 } 154 ), 155 ); 156 } 157 158 159 @("inheritance.struct.single") 160 @safe unittest { 161 shouldCompile( 162 Cpp( 163 q{ 164 struct Base { 165 int i; 166 }; 167 168 struct Derived: public Base { 169 double d; 170 }; 171 } 172 ), 173 D( 174 q{ 175 static assert(is(typeof(Derived.i) == int)); 176 static assert(is(typeof(Derived.d) == double)); 177 } 178 ), 179 ); 180 } 181 182 183 @("inheritance.struct.multiple") 184 @safe unittest { 185 shouldCompile( 186 Cpp( 187 q{ 188 struct Base0 { 189 int i; 190 }; 191 192 struct Base1 { 193 double d; 194 }; 195 196 struct Derived: public Base0, public Base1 { 197 198 }; 199 } 200 ), 201 D( 202 q{ 203 static assert(is(typeof(Derived.i) == int)); 204 static assert(is(typeof(Derived._base1.d) == double)); 205 } 206 ), 207 ); 208 } 209 210 211 @("hard_to_describe") 212 @safe unittest { 213 shouldCompile( 214 Cpp( 215 q{ 216 struct Member { 217 // having a constructor caused dpp to emit a `@disable this` 218 Member(const char*); 219 }; 220 221 template <typename T> 222 struct Template { 223 T payload; 224 }; 225 226 struct Struct { 227 Member member; 228 static Template<Struct> global; 229 }; 230 } 231 ), 232 D( 233 q{ 234 // just to check that the D code compiles 235 } 236 ), 237 ); 238 } 239 240 241 @("rule_of_5") 242 @safe unittest { 243 shouldCompile( 244 Cpp( 245 q{ 246 struct Struct { 247 Struct(Struct&&) = default; 248 Struct& operator=(Struct&&) = default; 249 Struct& operator=(const Struct&) = default; 250 }; 251 } 252 ), 253 D( 254 q{ 255 // just to check that the D code compiles 256 } 257 ), 258 ); 259 } 260 261 262 @("inner.return.nons") 263 @safe unittest { 264 shouldCompile( 265 Cpp( 266 q{ 267 struct Struct { 268 template<typename V> 269 struct Inner {}; 270 }; 271 const Struct::Inner<int>& inners(); 272 } 273 ), 274 D( 275 q{ 276 // just to check that the D code compiles 277 } 278 ), 279 ); 280 } 281 282 283 @("inner.return.ns.normal") 284 @safe unittest { 285 shouldCompile( 286 Cpp( 287 q{ 288 // it's important to have two different namespaces 289 namespace lens0 { 290 struct Struct { 291 template<typename V> 292 struct Inner {}; 293 }; 294 } 295 296 const lens0::Struct::Inner<int>& inners(); 297 } 298 ), 299 D( 300 q{ 301 // just to check that the D code compiles 302 } 303 ), 304 ); 305 } 306 307 308 @("inner.return.ns.using") 309 @safe unittest { 310 shouldCompile( 311 Cpp( 312 q{ 313 // it's important to have two different namespaces 314 namespace lens0 { 315 struct Struct { 316 template<typename V> 317 struct Inner {}; 318 }; 319 } 320 321 namespace lens1 { 322 using namespace lens0; 323 const Struct::Inner<int>& inners(); 324 } 325 } 326 ), 327 D( 328 q{ 329 // just to check that the D code compiles 330 } 331 ), 332 ); 333 } 334 335 336 @("virtual.base") 337 @safe unittest { 338 shouldCompile( 339 Cpp( 340 q{ 341 class Class { 342 public: 343 virtual void pureVirtualFunc() = 0; 344 virtual void virtualFunc(); 345 void normalFunc(); 346 }; 347 } 348 ), 349 D( 350 q{ 351 static assert(is(Class == class), "Class is not a class"); 352 } 353 ), 354 ); 355 } 356 357 358 @("virtual.child.override.normal") 359 @safe unittest { 360 shouldCompile( 361 Cpp( 362 q{ 363 class Base { 364 public: 365 virtual void pureVirtualFunc() = 0; 366 virtual void virtualFunc(); 367 void normalFunc(); 368 }; 369 370 class Derived: public Base { 371 public: 372 void pureVirtualFunc() override; 373 }; 374 } 375 ), 376 D( 377 q{ 378 static assert(is(Base == class), "Base is not a class"); 379 static assert(is(Derived == class), "Derived is not a class"); 380 static assert(is(Derived: Base), "Derived is not a child class of Base"); 381 382 auto d = new Derived; 383 d.pureVirtualFunc; 384 } 385 ), 386 ); 387 } 388 389 390 @("virtual.child.override.final") 391 @safe unittest { 392 shouldCompile( 393 Cpp( 394 q{ 395 struct A { 396 virtual bool has() const noexcept { return false; } 397 }; 398 399 struct B: A { 400 void foo(); 401 }; 402 403 struct C: B { 404 bool has() const noexcept final { return true; } 405 }; 406 } 407 ), 408 D( 409 q{ 410 auto c = new C(); 411 const bool res = c.has; 412 } 413 ), 414 ); 415 } 416 417 418 @("virtual.child.empty.normal") 419 @safe unittest { 420 shouldCompile( 421 Cpp( 422 q{ 423 class Base { 424 public: 425 virtual void virtualFunc(); 426 void normalFunc(); 427 }; 428 429 class Derived: public Base { 430 public: 431 432 }; 433 } 434 ), 435 D( 436 q{ 437 static assert(is(Base == class), "Base is not a class"); 438 static assert(is(Derived == class), "Derived is not a class"); 439 static assert(is(Derived: Base), "Derived is not a child class of Base"); 440 441 auto d = new Derived; 442 d.virtualFunc; 443 d.normalFunc; 444 } 445 ), 446 ); 447 } 448 449 450 @("virtual.child.empty.template") 451 @safe unittest { 452 shouldCompile( 453 Cpp( 454 q{ 455 template<typename T> 456 class Base { 457 public: 458 virtual void virtualFunc(); 459 void normalFunc(); 460 }; 461 462 class Derived: public Base<int> { 463 public: 464 465 }; 466 } 467 ), 468 D( 469 q{ 470 static assert(is(Derived == class), "Derived is not a class"); 471 static assert(is(Derived: Base!int), "Derived is not a child class of Base"); 472 473 auto d = new Derived; 474 d.virtualFunc; 475 d.normalFunc; 476 } 477 ), 478 ); 479 } 480 481 482 483 @("virtual.dtor") 484 @safe unittest { 485 shouldCompile( 486 Cpp( 487 q{ 488 class Class { 489 public: 490 virtual ~Class(); 491 }; 492 } 493 ), 494 D( 495 q{ 496 static assert(is(Class == class), "Class is not a class"); 497 } 498 ), 499 ); 500 } 501 502 503 @("virtual.opAssign") 504 @safe unittest { 505 shouldCompile( 506 Cpp( 507 q{ 508 class Class { 509 public: 510 virtual ~Class(); 511 Class& operator=(const Class&); 512 }; 513 } 514 ), 515 D( 516 q{ 517 static assert(is(Class == class), "Class is not a class"); 518 } 519 ), 520 ); 521 } 522 523 524 @("ctor.default") 525 @safe unittest { 526 shouldCompile( 527 Cpp( 528 q{ 529 class Base { 530 public: 531 virtual ~Base(); 532 Base() = default; 533 // the presence of the move ctor caused the compiler to fail with 534 // "cannot implicitly generate a default constructor" 535 // because the default ctor was ignored 536 Base(Base&&) = default; 537 }; 538 539 class Derived: public Base { 540 virtual void func(); 541 }; 542 } 543 ), 544 D( 545 q{ 546 static assert(is(Base == class), "Base is not a class"); 547 static assert(is(Derived == class), "Derived is not a class"); 548 static assert(is(Derived: Base), "Derived is not a child class of Base"); 549 } 550 ), 551 ); 552 } 553 554 555 @("ctor.using") 556 @safe unittest { 557 shouldCompile( 558 Cpp( 559 q{ 560 class Base { 561 public: 562 Base(int i); 563 Base(const Base&) = delete; 564 Base(Base&&) = delete; 565 virtual ~Base(); 566 }; 567 568 class Derived: public Base { 569 using Base::Base; 570 }; 571 } 572 ), 573 D( 574 q{ 575 static assert(is(Base == class), "Base is not a class"); 576 static assert(is(Derived == class), "Derived is not a class"); 577 static assert(is(Derived: Base), "Derived is not a child class of Base"); 578 579 auto d = new Derived(42); 580 } 581 ), 582 ["--hard-fail"], 583 ); 584 }