Skip to content

Commit 5d6eacc

Browse files
authored
Add isAggegregateType and isInstantiationOf to phobos.sys.traits. (#8981)
isAggregateType is the same as isAggregateType from std.traits but with tweaked documentation and examples. isInstantiationOf is the equivalent of std.traits' isInstanceOf. The documentation and tests have been updated, and an overload for partial instantiation has been added. The reason for the name change is that "instance" is not normally used with templates (instantiation is typically considered to be the correct term). Rather, instance is normally used to indicate that a value is an instance of a particular type. So, using isInstanceOf to check whether a type is an instantiation of a particular template seems like a misuse of the term and like it could easily cause confusion. The downside of course is that the new name is longer and harder to type, but while it's a trait that is necessary in some situations, IMHO, it's not needed frequently enough for the longer name to be a problem - particularly when it's a clearer name. I did try to simplify isInstantationOf's implementation so that it didn't need an alias overload, but I failed, because apparently, when typeof is used on the instantiation of a function template, the fact that it's a template instantation is lost. So, unfortunately, we're forced to operate on the function's symbol rather than its type to detect whether it's an instantation of a particular template. The documentation has been updated to include that information. I also tried to then make the alias overload not need a helper template so that fewer template instantiations would be needed, but that didn't work either, because the alias overload needs a template specialization to work, and I couldn't find a way to write an is expression that would have the same effect. So maybe, someone can improve the implementation later if they can figure that out, but since it's the same implementation as std.traits, we're not any worse off. And the overload which operates on aggregate types probably sees a lot more use anyway.
1 parent 7740a85 commit 5d6eacc

File tree

1 file changed

+262
-0
lines changed

1 file changed

+262
-0
lines changed

phobos/sys/traits.d

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,10 @@
5151
$(BOOKTABLE ,
5252
$(TR $(TH Category) $(TH Templates))
5353
$(TR $(TD Categories of types) $(TD
54+
$(LREF isAggregateType)
5455
$(LREF isDynamicArray)
5556
$(LREF isFloatingPoint)
57+
$(LREF isInstantiationOf)
5658
$(LREF isInteger)
5759
$(LREF isNumeric)
5860
$(LREF isPointer)
@@ -109,6 +111,33 @@
109111
+/
110112
module phobos.sys.traits;
111113

114+
/++
115+
Whether the given type is an "aggregate type" - i.e. a struct, class,
116+
interface, or union.
117+
+/
118+
enum isAggregateType(T) = is(T == struct) || is(T == class) || is(T == interface) || is(T == union);
119+
120+
@safe unittest
121+
{
122+
struct S {}
123+
class C {}
124+
interface I {}
125+
union U {}
126+
127+
static assert( isAggregateType!S);
128+
static assert( isAggregateType!C);
129+
static assert( isAggregateType!I);
130+
static assert( isAggregateType!U);
131+
static assert( isAggregateType!(const S));
132+
static assert( isAggregateType!(shared C));
133+
134+
static assert(!isAggregateType!int);
135+
static assert(!isAggregateType!string);
136+
static assert(!isAggregateType!(S*));
137+
static assert(!isAggregateType!(C[]));
138+
static assert(!isAggregateType!(I[string]));
139+
}
140+
112141
/++
113142
Whether the given type is a dynamic array (or what is sometimes referred to
114143
as a slice, since a dynamic array in D is a slice of memory).
@@ -1309,6 +1338,239 @@ enum isPointer(T) = is(T == U*, U);
13091338
}
13101339
}
13111340

1341+
/++
1342+
Evaluates to $(D true) if the given type or symbol is an instantiation of
1343+
the given template.
1344+
1345+
The overload which takes $(D T) operates on types and indicates whether an
1346+
aggregate type (i.e. struct, class, interface, or union) is an
1347+
instantiation of the given template.
1348+
1349+
The overload which takes $(D Symbol) operates on function templates,
1350+
because unlike with aggregate types, the type of a function does not retain
1351+
the fact that it was instantiated from a template. So, for functions, it's
1352+
necessary to pass the function itself as a symbol rather than pass the type
1353+
of the function.
1354+
1355+
The overload which takes $(D Symbol) also works with templates which are
1356+
not types or functions.
1357+
1358+
The single-argument overload makes it so that it can be partially
1359+
instantiated with the first argument, which will often be necessary with
1360+
template predicates.
1361+
+/
1362+
template isInstantiationOf(alias Template, T)
1363+
if (__traits(isTemplate, Template))
1364+
{
1365+
enum isInstantiationOf = is(T == Template!Args, Args...);
1366+
}
1367+
1368+
/++ Ditto +/
1369+
template isInstantiationOf(alias Template, alias Symbol)
1370+
if (__traits(isTemplate, Template))
1371+
{
1372+
enum impl(alias T : Template!Args, Args...) = true;
1373+
enum impl(alias T) = false;
1374+
enum isInstantiationOf = impl!Symbol;
1375+
}
1376+
1377+
/++ Ditto +/
1378+
template isInstantiationOf(alias Template)
1379+
if (__traits(isTemplate, Template))
1380+
{
1381+
enum isInstantiationOf(T) = is(T == Template!Args, Args...);
1382+
1383+
template isInstantiationOf(alias Symbol)
1384+
{
1385+
enum impl(alias T : Template!Args, Args...) = true;
1386+
enum impl(alias T) = false;
1387+
enum isInstantiationOf = impl!Symbol;
1388+
}
1389+
}
1390+
1391+
/// Examples of templated types.
1392+
@safe unittest
1393+
{
1394+
static struct S(T) {}
1395+
static class C(T) {}
1396+
1397+
static assert( isInstantiationOf!(S, S!int));
1398+
static assert( isInstantiationOf!(S, S!int));
1399+
static assert( isInstantiationOf!(S, S!string));
1400+
static assert( isInstantiationOf!(S, const S!string));
1401+
static assert( isInstantiationOf!(S, shared S!string));
1402+
static assert(!isInstantiationOf!(S, int));
1403+
static assert(!isInstantiationOf!(S, C!int));
1404+
static assert(!isInstantiationOf!(S, C!string));
1405+
static assert(!isInstantiationOf!(S, C!(S!int)));
1406+
1407+
static assert( isInstantiationOf!(C, C!int));
1408+
static assert( isInstantiationOf!(C, C!string));
1409+
static assert( isInstantiationOf!(C, const C!string));
1410+
static assert( isInstantiationOf!(C, shared C!string));
1411+
static assert(!isInstantiationOf!(C, int));
1412+
static assert(!isInstantiationOf!(C, S!int));
1413+
static assert(!isInstantiationOf!(C, S!string));
1414+
static assert(!isInstantiationOf!(C, S!(C!int)));
1415+
1416+
static struct Variadic(T...) {}
1417+
1418+
static assert( isInstantiationOf!(Variadic, Variadic!()));
1419+
static assert( isInstantiationOf!(Variadic, Variadic!int));
1420+
static assert( isInstantiationOf!(Variadic, Variadic!(int, string)));
1421+
static assert( isInstantiationOf!(Variadic, Variadic!(int, string, int)));
1422+
static assert( isInstantiationOf!(Variadic, const Variadic!(int, short)));
1423+
static assert( isInstantiationOf!(Variadic, shared Variadic!(int, short)));
1424+
static assert(!isInstantiationOf!(Variadic, int));
1425+
static assert(!isInstantiationOf!(Variadic, S!int));
1426+
static assert(!isInstantiationOf!(Variadic, C!int));
1427+
1428+
static struct ValueArg(int i) {}
1429+
static assert( isInstantiationOf!(ValueArg, ValueArg!42));
1430+
static assert( isInstantiationOf!(ValueArg, ValueArg!256));
1431+
static assert( isInstantiationOf!(ValueArg, const ValueArg!1024));
1432+
static assert( isInstantiationOf!(ValueArg, shared ValueArg!1024));
1433+
static assert(!isInstantiationOf!(ValueArg, int));
1434+
static assert(!isInstantiationOf!(ValueArg, S!int));
1435+
1436+
int i;
1437+
1438+
static struct AliasArg(alias Symbol) {}
1439+
static assert( isInstantiationOf!(AliasArg, AliasArg!42));
1440+
static assert( isInstantiationOf!(AliasArg, AliasArg!int));
1441+
static assert( isInstantiationOf!(AliasArg, AliasArg!i));
1442+
static assert( isInstantiationOf!(AliasArg, const AliasArg!i));
1443+
static assert( isInstantiationOf!(AliasArg, shared AliasArg!i));
1444+
static assert(!isInstantiationOf!(AliasArg, int));
1445+
static assert(!isInstantiationOf!(AliasArg, S!int));
1446+
1447+
// An uninstantiated template is not an instance of any template,
1448+
// not even itself.
1449+
static assert(!isInstantiationOf!(S, S));
1450+
static assert(!isInstantiationOf!(S, C));
1451+
static assert(!isInstantiationOf!(C, C));
1452+
static assert(!isInstantiationOf!(C, S));
1453+
1454+
// Variables of a templated type are not considered instantiations of that
1455+
// type. For templated types, the overload which takes a type must be used.
1456+
S!int s;
1457+
C!string c;
1458+
static assert(!isInstantiationOf!(S, s));
1459+
static assert(!isInstantiationOf!(C, c));
1460+
}
1461+
1462+
// Examples of templated functions.
1463+
@safe unittest
1464+
{
1465+
static int foo(T...)() { return 42; }
1466+
static void bar(T...)(T var) {}
1467+
static void baz(T)(T var) {}
1468+
static bool frobozz(alias pred)(int) { return true; }
1469+
1470+
static assert( isInstantiationOf!(foo, foo!int));
1471+
static assert( isInstantiationOf!(foo, foo!string));
1472+
static assert( isInstantiationOf!(foo, foo!(int, string)));
1473+
static assert(!isInstantiationOf!(foo, bar!int));
1474+
static assert(!isInstantiationOf!(foo, bar!string));
1475+
static assert(!isInstantiationOf!(foo, bar!(int, string)));
1476+
1477+
static assert( isInstantiationOf!(bar, bar!int));
1478+
static assert( isInstantiationOf!(bar, bar!string));
1479+
static assert( isInstantiationOf!(bar, bar!(int, string)));
1480+
static assert(!isInstantiationOf!(bar, foo!int));
1481+
static assert(!isInstantiationOf!(bar, foo!string));
1482+
static assert(!isInstantiationOf!(bar, foo!(int, string)));
1483+
1484+
static assert( isInstantiationOf!(baz, baz!int));
1485+
static assert( isInstantiationOf!(baz, baz!string));
1486+
static assert(!isInstantiationOf!(baz, foo!(int, string)));
1487+
1488+
static assert( isInstantiationOf!(frobozz, frobozz!(a => a)));
1489+
static assert( isInstantiationOf!(frobozz, frobozz!(a => a > 2)));
1490+
static assert(!isInstantiationOf!(frobozz, baz!int));
1491+
1492+
// Unfortunately, the function type is not considered an instantiation of
1493+
// the template, because that information is not part of the type, unlike
1494+
// with templated structs or classes.
1495+
static assert(!isInstantiationOf!(foo, typeof(foo!int)));
1496+
static assert(!isInstantiationOf!(bar, typeof(bar!int)));
1497+
}
1498+
1499+
// Examples of templates which aren't types or functions.
1500+
@safe unittest
1501+
{
1502+
template SingleArg(T) {}
1503+
template Variadic(T...) {}
1504+
template ValueArg(string s) {}
1505+
template Alias(alias symbol) {}
1506+
1507+
static assert( isInstantiationOf!(SingleArg, SingleArg!int));
1508+
static assert( isInstantiationOf!(SingleArg, SingleArg!string));
1509+
static assert(!isInstantiationOf!(SingleArg, int));
1510+
static assert(!isInstantiationOf!(SingleArg, Variadic!int));
1511+
1512+
static assert( isInstantiationOf!(Variadic, Variadic!()));
1513+
static assert( isInstantiationOf!(Variadic, Variadic!int));
1514+
static assert( isInstantiationOf!(Variadic, Variadic!string));
1515+
static assert( isInstantiationOf!(Variadic, Variadic!(short, int, long)));
1516+
static assert(!isInstantiationOf!(Variadic, int));
1517+
static assert(!isInstantiationOf!(Variadic, SingleArg!int));
1518+
1519+
static assert( isInstantiationOf!(ValueArg, ValueArg!"dlang"));
1520+
static assert( isInstantiationOf!(ValueArg, ValueArg!"foobar"));
1521+
static assert(!isInstantiationOf!(ValueArg, string));
1522+
static assert(!isInstantiationOf!(ValueArg, Variadic!string));
1523+
1524+
int i;
1525+
1526+
static assert( isInstantiationOf!(Alias, Alias!int));
1527+
static assert( isInstantiationOf!(Alias, Alias!42));
1528+
static assert( isInstantiationOf!(Alias, Alias!i));
1529+
static assert(!isInstantiationOf!(Alias, int));
1530+
static assert(!isInstantiationOf!(Alias, SingleArg!int));
1531+
}
1532+
1533+
/// Examples of partial instantation.
1534+
@safe unittest
1535+
{
1536+
static struct SingleArg(T) {}
1537+
static struct Variadic(T...) {}
1538+
1539+
alias isSingleArg = isInstantiationOf!SingleArg;
1540+
alias isVariadic = isInstantiationOf!Variadic;
1541+
1542+
static assert( isSingleArg!(SingleArg!int));
1543+
static assert( isSingleArg!(const SingleArg!int));
1544+
static assert(!isSingleArg!int);
1545+
static assert(!isSingleArg!(Variadic!int));
1546+
1547+
static assert( isVariadic!(Variadic!()));
1548+
static assert( isVariadic!(Variadic!int));
1549+
static assert( isVariadic!(shared Variadic!int));
1550+
static assert( isVariadic!(Variadic!(int, string)));
1551+
static assert(!isVariadic!int);
1552+
static assert(!isVariadic!(SingleArg!int));
1553+
1554+
T foo(T)(T t) { return t; }
1555+
T likeFoo(T)(T t) { return t; }
1556+
bool bar(alias pred)(int i) { return pred(i); }
1557+
1558+
alias isFoo = isInstantiationOf!foo;
1559+
alias isBar = isInstantiationOf!bar;
1560+
1561+
static assert( isFoo!(foo!int));
1562+
static assert( isFoo!(foo!string));
1563+
static assert(!isFoo!int);
1564+
static assert(!isFoo!(likeFoo!int));
1565+
static assert(!isFoo!(bar!(a => true)));
1566+
1567+
static assert( isBar!(bar!(a => true)));
1568+
static assert( isBar!(bar!(a => a > 2)));
1569+
static assert(!isBar!int);
1570+
static assert(!isBar!(foo!int));
1571+
static assert(!isBar!(likeFoo!int));
1572+
}
1573+
13121574
/++
13131575
Evaluates to an $(D AliasSeq) containing the members of an enum type.
13141576

0 commit comments

Comments
 (0)