It acts just like ==, but it's a template.
enum a = 42; static assert( isEqual!(a, 42)); static assert( isEqual!(20, 10 + 10)); static assert(!isEqual!(a, 120)); static assert(!isEqual!(77, 19 * 7 + 2)); // b cannot be read at compile time, so it won't work with isEqual. int b = 99; static assert(!__traits(compiles, isEqual!(b, 99)));
Comparing some of the differences between an AliasSeq of enum members and an array of enum values created from an AliasSeq of enum members.
1 import phobos.sys.meta : AliasSeq, Unique; 2 3 enum E 4 { 5 a = 0, 6 b = 22, 7 c = 33, 8 d = 0, 9 e = 256, 10 f = 33, 11 g = 7 12 } 13 14 alias uniqueMembers = Unique!(isEqual, EnumMembers!E); 15 static assert(uniqueMembers.length == 5); 16 17 static assert(__traits(isSame, uniqueMembers[0], E.a)); 18 static assert(__traits(isSame, uniqueMembers[1], E.b)); 19 static assert(__traits(isSame, uniqueMembers[2], E.c)); 20 static assert(__traits(isSame, uniqueMembers[3], E.e)); 21 static assert(__traits(isSame, uniqueMembers[4], E.g)); 22 23 static assert(__traits(identifier, uniqueMembers[0]) == "a"); 24 static assert(__traits(identifier, uniqueMembers[1]) == "b"); 25 static assert(__traits(identifier, uniqueMembers[2]) == "c"); 26 static assert(__traits(identifier, uniqueMembers[3]) == "e"); 27 static assert(__traits(identifier, uniqueMembers[4]) == "g"); 28 29 // Same value but different symbol. 30 static assert(uniqueMembers[0] == E.d); 31 static assert(!__traits(isSame, uniqueMembers[0], E.d)); 32 33 // is expressions compare types, not symbols or values, and these AliasSeqs 34 // contain the list of symbols for the enum members, not types, so the is 35 // expression evaluates to false even though the symbols are the same. 36 static assert(!is(uniqueMembers == AliasSeq!(E.a, E.b, E.c, E.e, E.g))); 37 38 // Once the members are converted to an array, the types are the same, and 39 // the values are the same, but the symbols are not the same. Instead of 40 // being the symbols E.a, E.b, etc., they're just values with the type E 41 // which match the values of E.a, E.b, etc. 42 enum arr = [uniqueMembers]; 43 static assert(is(typeof(arr) == E[])); 44 45 static assert(arr == [E.a, E.b, E.c, E.e, E.g]); 46 static assert(arr == [E.d, E.b, E.f, E.e, E.g]); 47 48 static assert(!__traits(isSame, arr[0], E.a)); 49 static assert(!__traits(isSame, arr[1], E.b)); 50 static assert(!__traits(isSame, arr[2], E.c)); 51 static assert(!__traits(isSame, arr[3], E.e)); 52 static assert(!__traits(isSame, arr[4], E.g)); 53 54 // Since arr[0] is just a value of type E, it's no longer the symbol, E.a, 55 // even though its type is E, and its value is the same as that of E.a. And 56 // unlike the actual members of an enum, an element of an array does not 57 // have an identifier, so __traits(identifier, ...) doesn't work with it. 58 static assert(!__traits(compiles, __traits(identifier, arr[0]))); 59 60 // Similarly, once an enum member from the AliasSeq is assigned to a 61 // variable, __traits(identifer, ...) operates on the variable, not the 62 // symbol from the AliasSeq or the value of the variable. 63 auto var = uniqueMembers[0]; 64 static assert(__traits(identifier, var) == "var"); 65 66 // The same with a manifest constant. 67 enum constant = uniqueMembers[0]; 68 static assert(__traits(identifier, constant) == "constant");
Whether the given values are equal per ==.
All this does is lhs == rhs but in an eponymous template, so most code shouldn't use it. It's intended to be used in conjunction with templates that take a template predicate - such as those 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.
Note that in most cases, even when comparing values at compile time, using isEqual makes no sense, because you can use CTFE to just compare two values (or expressions which evaluate to values), but in rare cases where you need to compare symbols in an AliasSeq by value with a template predicate while still leaving them as symbols in an AliasSeq, then isEqual would be needed.
A prime example of this would be Unique!(isEqual, EnumMembers!MyEnum), which results in an AliasSeq containing the list of members of MyEnum but without any duplicate values (e.g. to use when doing code generation to create a final switch).
Alternatively, code such as [EnumMembers!MyEnum].sort().unique() could be used to get a dynamic array of the enum members with no duplicate values via CTFE, thus avoiding the need for template predicates or anything from phobos.sys.meta. However, you then have a dynamic array of enum values rather than an AliasSeq of symbols for those enum members, which affects what you can do with type introspection. So, which approach is better depends on what the code needs to do with the enum members.
In general, however, if code doesn't need an AliasSeq, and an array of values will do the trick, then it's more efficient to operate on an array of values with CTFE and avoid using isEqual or other templates to operate on the values as an AliasSeq.