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 }