isImplicitlyConvertible

Whether the type From is implicitly convertible to the type To.

Note that template constraints should be very careful about when they test for implicit conversions and in general should prefer to either test for an exact set of types or for types which compile with a particular piece of code rather than being designed to accept any type which implicitly converts to a particular type.

This is because having a type pass a template constraint based on an implicit conversion but then not have the implicit conversion actually take place (which it won't unless the template does something to force it internally) can lead to either compilation errors or subtle behavioral differences - and even when the conversion is done explicitly within a templated function, since it's not done at the call site, it can still lead to subtle bugs in some cases (e.g. if slicing a static array is involved).

For situations where code needs to verify that a type is implicitly convertible based solely on its qualifiers, isQualifierConvertible would be a more appropriate choice than isImplicitlyConvertible.

Given how trivial the is expression for isImplicitlyConvertible is - is(To : From) - this trait is provided primarily so that it can be used in conjunction with templates that use a template predicate (such as many of the templates in phobos.sys.meta).

The single-argument overload makes it so that it can be partially instantiated with the first argument, which will often be necessary with template predicates.

  1. eponymoustemplate isImplicitlyConvertible(From, To)
  2. template isImplicitlyConvertible(From)
    template isImplicitlyConvertible (
    From
    ) {}

Examples

1 static assert( isImplicitlyConvertible!(byte, long));
2 static assert( isImplicitlyConvertible!(ushort, long));
3 static assert( isImplicitlyConvertible!(int, long));
4 static assert( isImplicitlyConvertible!(long, long));
5 static assert( isImplicitlyConvertible!(ulong, long));
6 
7 static assert( isImplicitlyConvertible!(ubyte, int));
8 static assert( isImplicitlyConvertible!(short, int));
9 static assert( isImplicitlyConvertible!(int, int));
10 static assert( isImplicitlyConvertible!(uint, int));
11 static assert(!isImplicitlyConvertible!(long, int));
12 static assert(!isImplicitlyConvertible!(ulong, int));
13 
14 static assert(!isImplicitlyConvertible!(int, string));
15 static assert(!isImplicitlyConvertible!(int, int[]));
16 static assert(!isImplicitlyConvertible!(int, int*));
17 
18 static assert(!isImplicitlyConvertible!(string, int));
19 static assert(!isImplicitlyConvertible!(int[], int));
20 static assert(!isImplicitlyConvertible!(int*, int));
21 
22 // For better or worse, bool and the built-in character types will
23 // implicitly convert to integer or floating-point types if the target type
24 // is large enough. Sometimes, this is desirable, whereas at other times,
25 // it can have very surprising results, so it's one reason why code should
26 // be very careful when testing for implicit conversions.
27 static assert( isImplicitlyConvertible!(bool, int));
28 static assert( isImplicitlyConvertible!(char, int));
29 static assert( isImplicitlyConvertible!(wchar, int));
30 static assert( isImplicitlyConvertible!(dchar, int));
31 
32 static assert( isImplicitlyConvertible!(bool, ubyte));
33 static assert( isImplicitlyConvertible!(char, ubyte));
34 static assert(!isImplicitlyConvertible!(wchar, ubyte));
35 static assert(!isImplicitlyConvertible!(dchar, ubyte));
36 
37 static assert( isImplicitlyConvertible!(bool, double));
38 static assert( isImplicitlyConvertible!(char, double));
39 static assert( isImplicitlyConvertible!(wchar, double));
40 static assert( isImplicitlyConvertible!(dchar, double));
41 
42 // Value types can be implicitly converted regardless of their qualifiers
43 // thanks to the fact that they're copied.
44 static assert( isImplicitlyConvertible!(int, int));
45 static assert( isImplicitlyConvertible!(const int, int));
46 static assert( isImplicitlyConvertible!(immutable int, int));
47 static assert( isImplicitlyConvertible!(inout int, int));
48 
49 static assert( isImplicitlyConvertible!(int, const int));
50 static assert( isImplicitlyConvertible!(int, immutable int));
51 static assert( isImplicitlyConvertible!(int, inout int));
52 
53 // Reference types are far more restrictive about which implicit conversions
54 // they allow, because qualifiers in D are transitive.
55 static assert( isImplicitlyConvertible!(int*, int*));
56 static assert(!isImplicitlyConvertible!(const int*, int*));
57 static assert(!isImplicitlyConvertible!(immutable int*, int*));
58 
59 static assert( isImplicitlyConvertible!(int*, const int*));
60 static assert( isImplicitlyConvertible!(const int*, const int*));
61 static assert( isImplicitlyConvertible!(immutable int*, const int*));
62 
63 static assert(!isImplicitlyConvertible!(int*, immutable int*));
64 static assert(!isImplicitlyConvertible!(const int*, immutable int*));
65 static assert( isImplicitlyConvertible!(immutable int*, immutable int*));
66 
67 // Note that inout gets a bit weird, since it's only used with function
68 // parameters, and it's a stand-in for whatever mutability qualifiers the
69 // type actually has. So, a function parameter that's inout accepts any
70 // mutability, but you can't actually implicitly convert to inout, because
71 // it's unknown within the function what the actual mutability of the type
72 // is. It will differ depending on the function arguments of a specific
73 // call to that function, so the same code has to work with all combinations
74 // of mutability qualifiers.
75 static assert(!isImplicitlyConvertible!(int*, inout int*));
76 static assert(!isImplicitlyConvertible!(const int*, inout int*));
77 static assert(!isImplicitlyConvertible!(immutable int*, inout int*));
78 static assert( isImplicitlyConvertible!(inout int*, inout int*));
79 
80 static assert(!isImplicitlyConvertible!(inout int*, int*));
81 static assert( isImplicitlyConvertible!(inout int*, const int*));
82 static assert(!isImplicitlyConvertible!(inout int*, immutable int*));
83 
84 // Enums implicitly convert to their base type.
85 enum E : int
86 {
87     a = 42
88 }
89 static assert( isImplicitlyConvertible!(E, int));
90 static assert( isImplicitlyConvertible!(E, long));
91 static assert(!isImplicitlyConvertible!(E, int[]));
92 
93 // Structs only implicit convert to another type via declaring an
94 // alias this.
95 static struct S
96 {
97     int i;
98 }
99 static assert(!isImplicitlyConvertible!(S, int));
100 static assert(!isImplicitlyConvertible!(S, long));
101 static assert(!isImplicitlyConvertible!(S, string));
102 
103 static struct AliasThis
104 {
105     int i;
106     alias this = i;
107 }
108 static assert( isImplicitlyConvertible!(AliasThis, int));
109 static assert( isImplicitlyConvertible!(AliasThis, long));
110 static assert(!isImplicitlyConvertible!(AliasThis, string));
111 
112 static struct AliasThis2
113 {
114     AliasThis at;
115     alias this = at;
116 }
117 static assert( isImplicitlyConvertible!(AliasThis2, AliasThis));
118 static assert( isImplicitlyConvertible!(AliasThis2, int));
119 static assert( isImplicitlyConvertible!(AliasThis2, long));
120 static assert(!isImplicitlyConvertible!(AliasThis2, string));
121 
122 static struct AliasThis3
123 {
124     AliasThis2 at;
125     alias this = at;
126 }
127 static assert( isImplicitlyConvertible!(AliasThis3, AliasThis2));
128 static assert( isImplicitlyConvertible!(AliasThis3, AliasThis));
129 static assert( isImplicitlyConvertible!(AliasThis3, int));
130 static assert( isImplicitlyConvertible!(AliasThis3, long));
131 static assert(!isImplicitlyConvertible!(AliasThis3, string));
132 
133 // D does not support implicit conversions via construction.
134 static struct Cons
135 {
136     this(int i)
137     {
138         this.i = i;
139     }
140 
141     int i;
142 }
143 static assert(!isImplicitlyConvertible!(int, Cons));
144 
145 // Classes support implicit conversion based on their class and
146 // interface hierarchies.
147 static interface I1 {}
148 static class Base : I1 {}
149 
150 static interface I2 {}
151 static class Foo : Base, I2 {}
152 
153 static class Bar : Base {}
154 
155 static assert( isImplicitlyConvertible!(Base, Base));
156 static assert(!isImplicitlyConvertible!(Base, Foo));
157 static assert(!isImplicitlyConvertible!(Base, Bar));
158 static assert( isImplicitlyConvertible!(Base, I1));
159 static assert(!isImplicitlyConvertible!(Base, I2));
160 
161 static assert( isImplicitlyConvertible!(Foo, Base));
162 static assert( isImplicitlyConvertible!(Foo, Foo));
163 static assert(!isImplicitlyConvertible!(Foo, Bar));
164 static assert( isImplicitlyConvertible!(Foo, I1));
165 static assert( isImplicitlyConvertible!(Foo, I2));
166 
167 static assert( isImplicitlyConvertible!(Bar, Base));
168 static assert(!isImplicitlyConvertible!(Bar, Foo));
169 static assert( isImplicitlyConvertible!(Bar, Bar));
170 static assert( isImplicitlyConvertible!(Bar, I1));
171 static assert(!isImplicitlyConvertible!(Bar, I2));
172 
173 static assert(!isImplicitlyConvertible!(I1, Base));
174 static assert(!isImplicitlyConvertible!(I1, Foo));
175 static assert(!isImplicitlyConvertible!(I1, Bar));
176 static assert( isImplicitlyConvertible!(I1, I1));
177 static assert(!isImplicitlyConvertible!(I1, I2));
178 
179 static assert(!isImplicitlyConvertible!(I2, Base));
180 static assert(!isImplicitlyConvertible!(I2, Foo));
181 static assert(!isImplicitlyConvertible!(I2, Bar));
182 static assert(!isImplicitlyConvertible!(I2, I1));
183 static assert( isImplicitlyConvertible!(I2, I2));
184 
185 // Note that arrays are not implicitly convertible even when their elements
186 // are implicitly convertible.
187 static assert(!isImplicitlyConvertible!(ubyte[], uint[]));
188 static assert(!isImplicitlyConvertible!(Foo[], Base[]));
189 static assert(!isImplicitlyConvertible!(Bar[], Base[]));
190 
191 // However, like with pointers, dynamic arrays are convertible based on
192 // constness.
193 static assert( isImplicitlyConvertible!(Base[], const Base[]));
194 static assert( isImplicitlyConvertible!(Base[], const(Base)[]));
195 static assert(!isImplicitlyConvertible!(Base[], immutable(Base)[]));
196 static assert(!isImplicitlyConvertible!(const Base[], immutable Base[]));
197 static assert( isImplicitlyConvertible!(const Base[], const Base[]));
198 static assert(!isImplicitlyConvertible!(const Base[], immutable Base[]));

isImplicitlyConvertible can be used with partial instantiation so that it can be passed to a template which takes a unary predicate.

import phobos.sys.meta : AliasSeq, all, indexOf;

// byte is implicitly convertible to byte, short, int, and long.
static assert(all!(isImplicitlyConvertible!byte, short, int, long));

// const(char)[] at index 2 is the first type in the AliasSeq which string
// can be implicitly converted to.
alias Types = AliasSeq!(int, char[], const(char)[], string, int*);
static assert(indexOf!(isImplicitlyConvertible!string, Types) == 2);

See Also

Meta