hasComplexCopying

Whether copying an object of the given type involves either a user-defined copy / postblit constructor or a compiler-generated copy / postblit constructor rather than using the default copying behavior (which would use memcpy).

The compiler will generate a copy / postblit constructor for a struct when a member variable of that struct defines a copy / postblit constructor.

Note that hasComplexCopying is also true for static arrays whose element type has a copy constructor or postblit constructor, since while the static array itself does not have a copy constructor or postblit constructor, the compiler must use the copy / postblit constructor of the elements when copying the static array.

Due to https://issues.dlang.org/show_bug.cgi?id=24833, enums never have complex copying even if their base type does. Their copy / postblit constructor is never called, resulting in incorrect behavior for such enums. So, because the compiler does not treat them as having complex copying, hasComplexCopying is false for them.

No other types (including class references, pointers, and unions) ever have a copy constructor or postblit constructor and thus hasComplexCopying is never true for them. It is particularly important to note that unions never have a copy constructor or postblit constructor, so if a struct contains a union which contains one or more members which have a copy constructor or postblit constructor, that struct will have to have a user-defined copy constructor or posthblit constructor which explicitly copies the correct member of the union if you don't want the current value of the union to simply be memcopied when copying the struct.

If a particular piece of code cares about the existence of a copy constructor or postblit constructor specifically rather than if a type has one or the other, the traits __traits(hasCopyConstructor, T) and __traits(hasPostblit, T) can be used, though note that they will not be true for static arrays.

template hasComplexCopying (
T
) {}

Examples

1 static assert(!hasComplexCopying!int);
2 static assert(!hasComplexCopying!real);
3 static assert(!hasComplexCopying!string);
4 static assert(!hasComplexCopying!(int[]));
5 static assert(!hasComplexCopying!(int[42]));
6 static assert(!hasComplexCopying!(int[string]));
7 static assert(!hasComplexCopying!Object);
8 
9 static struct NoCopyCtor1
10 {
11     int i;
12 }
13 static assert(!hasComplexCopying!NoCopyCtor1);
14 static assert(!__traits(hasCopyConstructor, NoCopyCtor1));
15 static assert(!__traits(hasPostblit, NoCopyCtor1));
16 
17 static struct NoCopyCtor2
18 {
19     int i;
20 
21     this(int i)
22     {
23         this.i = i;
24     }
25 }
26 static assert(!hasComplexCopying!NoCopyCtor2);
27 static assert(!__traits(hasCopyConstructor, NoCopyCtor2));
28 static assert(!__traits(hasPostblit, NoCopyCtor2));
29 
30 struct HasCopyCtor
31 {
32     this(ref HasCopyCtor)
33     {
34     }
35 }
36 static assert( hasComplexCopying!HasCopyCtor);
37 static assert( __traits(hasCopyConstructor, HasCopyCtor));
38 static assert(!__traits(hasPostblit, HasCopyCtor));
39 
40 // hasComplexCopying does not take constness into account.
41 // Code that wants to check whether copying works will need to test
42 // __traits(isCopyable, T) or test that copying compiles.
43 static assert( hasComplexCopying!(const HasCopyCtor));
44 static assert( __traits(hasCopyConstructor, const HasCopyCtor));
45 static assert(!__traits(hasPostblit, const HasCopyCtor));
46 static assert(!__traits(isCopyable, const HasCopyCtor));
47 static assert(!__traits(compiles, { const HasCopyCtor h;
48                                     auto h2 = h; }));
49 static assert(!is(typeof({ const HasCopyCtor h1;
50                            auto h2 = h1; })));
51 
52 // An rvalue constructor is not a copy constructor.
53 struct HasRValueCtor
54 {
55     this(HasRValueCtor)
56     {
57     }
58 }
59 static assert(!hasComplexCopying!HasRValueCtor);
60 static assert(!__traits(hasCopyConstructor, HasRValueCtor));
61 static assert(!__traits(hasPostblit, HasRValueCtor));
62 
63 struct HasPostblit
64 {
65     this(this)
66     {
67     }
68 }
69 static assert( hasComplexCopying!HasPostblit);
70 static assert(!__traits(hasCopyConstructor, HasPostblit));
71 static assert( __traits(hasPostblit, HasPostblit));
72 
73 // The compiler will generate a copy constructor if a member variable
74 // has one.
75 static struct HasMemberWithCopyCtor
76 {
77     HasCopyCtor s;
78 }
79 static assert( hasComplexCopying!HasMemberWithCopyCtor);
80 
81 // The compiler will generate a postblit constructor if a member variable
82 // has one.
83 static struct HasMemberWithPostblit
84 {
85     HasPostblit s;
86 }
87 static assert( hasComplexCopying!HasMemberWithPostblit);
88 
89 // If a struct has @disabled copying, hasComplexCopying is still true.
90 // Code that wants to check whether copying works will need to test
91 // __traits(isCopyable, T) or test that copying compiles.
92 static struct DisabledCopying
93 {
94     @disable this(this);
95     @disable this(ref DisabledCopying);
96 }
97 static assert( hasComplexCopying!DisabledCopying);
98 static assert(!__traits(isCopyable, DisabledCopying));
99 static assert(!__traits(compiles, { DisabledCopying dc1;
100                                     auto dc2 = dc1; }));
101 static assert(!is(typeof({ DisabledCopying dc1;
102                            auto dc2 = dc1; })));
103 
104 // Static arrays have complex copying if their elements do.
105 static assert( hasComplexCopying!(HasCopyCtor[1]));
106 static assert( hasComplexCopying!(HasPostblit[1]));
107 
108 // Static arrays with no elements do not have complex copying, because
109 // there's nothing to copy.
110 static assert(!hasComplexCopying!(HasCopyCtor[0]));
111 static assert(!hasComplexCopying!(HasPostblit[0]));
112 
113 // Dynamic arrays do not have complex copying, because copying them
114 // just slices them rather than copying their elements.
115 static assert(!hasComplexCopying!(HasCopyCtor[]));
116 static assert(!hasComplexCopying!(HasPostblit[]));
117 
118 // Classes and unions do not have complex copying even if they have
119 // members which do.
120 class C
121 {
122     HasCopyCtor s;
123 }
124 static assert(!hasComplexCopying!C);
125 
126 union U
127 {
128     HasCopyCtor s;
129 }
130 static assert(!hasComplexCopying!U);
131 
132 // https://issues.dlang.org/show_bug.cgi?id=24833
133 // This static assertion fails, because the compiler
134 // currently ignores assignment operators for enum types.
135 enum E : HasCopyCtor { a = HasCopyCtor.init }
136 //static assert( hasComplexCopying!E);

See Also

Meta