phobos/std/typetuple.d

1030 lines
26 KiB
D

// Written in the D programming language.
/**
* Templates with which to manipulate type tuples (also known as type lists).
*
* Some operations on type tuples are built in to the language,
* such as TL[$(I n)] which gets the $(I n)th type from the
* type tuple. TL[$(I lwr) .. $(I upr)] returns a new type
* list that is a slice of the old one.
*
* Several templates in this module use or operate on eponymous templates that
* take a single argument and evaluate to a boolean constant. Such templates
* are referred to as $(I template predicates).
*
* References:
* Based on ideas in Table 3.1 from
* $(LINK2 http://amazon.com/exec/obidos/ASIN/0201704315/ref=ase_classicempire/102-2957199-2585768,
* Modern C++ Design),
* Andrei Alexandrescu (Addison-Wesley Professional, 2001)
* Macros:
* WIKI = Phobos/StdTypeTuple
*
* Copyright: Copyright Digital Mars 2005 - 2009.
* License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
* Authors:
* $(WEB digitalmars.com, Walter Bright),
* $(WEB klickverbot.at, David Nadlinger)
* Source: $(PHOBOSSRC std/_typetuple.d)
*/
/* Copyright Digital Mars 2005 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module std.typetuple;
/**
* Creates a typetuple out of a sequence of zero or more types.
*/
template TypeTuple(TList...)
{
alias TypeTuple = TList;
}
///
unittest
{
import std.typetuple;
alias TL = TypeTuple!(int, double);
int foo(TL td) // same as int foo(int, double);
{
return td[0] + cast(int)td[1];
}
}
///
unittest
{
alias TL = TypeTuple!(int, double);
alias Types = TypeTuple!(TL, char);
static assert(is(Types == TypeTuple!(int, double, char)));
}
/**
* Returns the index of the first occurrence of type T in the
* sequence of zero or more types TList.
* If not found, -1 is returned.
*/
template staticIndexOf(T, TList...)
{
enum staticIndexOf = genericIndexOf!(T, TList).index;
}
/// Ditto
template staticIndexOf(alias T, TList...)
{
enum staticIndexOf = genericIndexOf!(T, TList).index;
}
///
unittest
{
import std.typetuple;
import std.stdio;
void foo()
{
writefln("The index of long is %s",
staticIndexOf!(long, TypeTuple!(int, long, double)));
// prints: The index of long is 1
}
}
// [internal]
private template genericIndexOf(args...)
if (args.length >= 1)
{
alias e = Alias!(args[0]);
alias tuple = args[1 .. $];
static if (tuple.length)
{
alias head = Alias!(tuple[0]);
alias tail = tuple[1 .. $];
static if (isSame!(e, head))
{
enum index = 0;
}
else
{
enum next = genericIndexOf!(e, tail).index;
enum index = (next == -1) ? -1 : 1 + next;
}
}
else
{
enum index = -1;
}
}
unittest
{
static assert(staticIndexOf!( byte, byte, short, int, long) == 0);
static assert(staticIndexOf!(short, byte, short, int, long) == 1);
static assert(staticIndexOf!( int, byte, short, int, long) == 2);
static assert(staticIndexOf!( long, byte, short, int, long) == 3);
static assert(staticIndexOf!( char, byte, short, int, long) == -1);
static assert(staticIndexOf!( -1, byte, short, int, long) == -1);
static assert(staticIndexOf!(void) == -1);
static assert(staticIndexOf!("abc", "abc", "def", "ghi", "jkl") == 0);
static assert(staticIndexOf!("def", "abc", "def", "ghi", "jkl") == 1);
static assert(staticIndexOf!("ghi", "abc", "def", "ghi", "jkl") == 2);
static assert(staticIndexOf!("jkl", "abc", "def", "ghi", "jkl") == 3);
static assert(staticIndexOf!("mno", "abc", "def", "ghi", "jkl") == -1);
static assert(staticIndexOf!( void, "abc", "def", "ghi", "jkl") == -1);
static assert(staticIndexOf!(42) == -1);
static assert(staticIndexOf!(void, 0, "void", void) == 2);
static assert(staticIndexOf!("void", 0, void, "void") == 2);
}
/// Kept for backwards compatibility
alias IndexOf = staticIndexOf;
/**
* Returns a typetuple created from TList with the first occurrence,
* if any, of T removed.
*/
template Erase(T, TList...)
{
alias Erase = GenericErase!(T, TList).result;
}
/// Ditto
template Erase(alias T, TList...)
{
alias Erase = GenericErase!(T, TList).result;
}
///
unittest
{
alias Types = TypeTuple!(int, long, double, char);
alias TL = Erase!(long, Types);
static assert(is(TL == TypeTuple!(int, double, char)));
}
// [internal]
private template GenericErase(args...)
if (args.length >= 1)
{
alias e = Alias!(args[0]);
alias tuple = args[1 .. $] ;
static if (tuple.length)
{
alias head = Alias!(tuple[0]);
alias tail = tuple[1 .. $];
static if (isSame!(e, head))
alias result = tail;
else
alias result = TypeTuple!(head, GenericErase!(e, tail).result);
}
else
{
alias result = TypeTuple!();
}
}
unittest
{
static assert(Pack!(Erase!(int,
short, int, int, 4)).
equals!(short, int, 4));
static assert(Pack!(Erase!(1,
real, 3, 1, 4, 1, 5, 9)).
equals!(real, 3, 4, 1, 5, 9));
}
/**
* Returns a typetuple created from TList with the all occurrences,
* if any, of T removed.
*/
template EraseAll(T, TList...)
{
alias EraseAll = GenericEraseAll!(T, TList).result;
}
/// Ditto
template EraseAll(alias T, TList...)
{
alias EraseAll = GenericEraseAll!(T, TList).result;
}
///
unittest
{
alias Types = TypeTuple!(int, long, long, int);
alias TL = EraseAll!(long, Types);
static assert(is(TL == TypeTuple!(int, int)));
}
// [internal]
private template GenericEraseAll(args...)
if (args.length >= 1)
{
alias e = Alias!(args[0]);
alias tuple = args[1 .. $];
static if (tuple.length)
{
alias head = Alias!(tuple[0]);
alias tail = tuple[1 .. $];
alias next = GenericEraseAll!(e, tail).result;
static if (isSame!(e, head))
alias result = next;
else
alias result = TypeTuple!(head, next);
}
else
{
alias result = TypeTuple!();
}
}
unittest
{
static assert(Pack!(EraseAll!(int,
short, int, int, 4)).
equals!(short, 4));
static assert(Pack!(EraseAll!(1,
real, 3, 1, 4, 1, 5, 9)).
equals!(real, 3, 4, 5, 9));
}
/**
* Returns a typetuple created from TList with the all duplicate
* types removed.
*/
template NoDuplicates(TList...)
{
static if (TList.length == 0)
alias NoDuplicates = TList;
else
alias NoDuplicates =
TypeTuple!(TList[0], NoDuplicates!(EraseAll!(TList[0], TList[1 .. $])));
}
///
unittest
{
alias Types = TypeTuple!(int, long, long, int, float);
alias TL = NoDuplicates!(Types);
static assert(is(TL == TypeTuple!(int, long, float)));
}
unittest
{
static assert(
Pack!(
NoDuplicates!(1, int, 1, NoDuplicates, int, NoDuplicates, real))
.equals!(1, int, NoDuplicates, real));
}
/**
* Returns a typetuple created from TList with the first occurrence
* of type T, if found, replaced with type U.
*/
template Replace(T, U, TList...)
{
alias Replace = GenericReplace!(T, U, TList).result;
}
/// Ditto
template Replace(alias T, U, TList...)
{
alias Replace = GenericReplace!(T, U, TList).result;
}
/// Ditto
template Replace(T, alias U, TList...)
{
alias Replace = GenericReplace!(T, U, TList).result;
}
/// Ditto
template Replace(alias T, alias U, TList...)
{
alias Replace = GenericReplace!(T, U, TList).result;
}
///
unittest
{
alias Types = TypeTuple!(int, long, long, int, float);
alias TL = Replace!(long, char, Types);
static assert(is(TL == TypeTuple!(int, char, long, int, float)));
}
// [internal]
private template GenericReplace(args...)
if (args.length >= 2)
{
alias from = Alias!(args[0]);
alias to = Alias!(args[1]);
alias tuple = args[2 .. $];
static if (tuple.length)
{
alias head = Alias!(tuple[0]);
alias tail = tuple[1 .. $];
static if (isSame!(from, head))
alias result = TypeTuple!(to, tail);
else
alias result = TypeTuple!(head,
GenericReplace!(from, to, tail).result);
}
else
{
alias result = TypeTuple!();
}
}
unittest
{
static assert(Pack!(Replace!(byte, ubyte,
short, byte, byte, byte)).
equals!(short, ubyte, byte, byte));
static assert(Pack!(Replace!(1111, byte,
2222, 1111, 1111, 1111)).
equals!(2222, byte, 1111, 1111));
static assert(Pack!(Replace!(byte, 1111,
short, byte, byte, byte)).
equals!(short, 1111, byte, byte));
static assert(Pack!(Replace!(1111, "11",
2222, 1111, 1111, 1111)).
equals!(2222, "11", 1111, 1111));
}
/**
* Returns a typetuple created from TList with all occurrences
* of type T, if found, replaced with type U.
*/
template ReplaceAll(T, U, TList...)
{
alias ReplaceAll = GenericReplaceAll!(T, U, TList).result;
}
/// Ditto
template ReplaceAll(alias T, U, TList...)
{
alias ReplaceAll = GenericReplaceAll!(T, U, TList).result;
}
/// Ditto
template ReplaceAll(T, alias U, TList...)
{
alias ReplaceAll = GenericReplaceAll!(T, U, TList).result;
}
/// Ditto
template ReplaceAll(alias T, alias U, TList...)
{
alias ReplaceAll = GenericReplaceAll!(T, U, TList).result;
}
///
unittest
{
alias Types = TypeTuple!(int, long, long, int, float);
alias TL = ReplaceAll!(long, char, Types);
static assert(is(TL == TypeTuple!(int, char, char, int, float)));
}
// [internal]
private template GenericReplaceAll(args...)
if (args.length >= 2)
{
alias from = Alias!(args[0]);
alias to = Alias!(args[1]);
alias tuple = args[2 .. $];
static if (tuple.length)
{
alias head = Alias!(tuple[0]);
alias tail = tuple[1 .. $];
alias next = GenericReplaceAll!(from, to, tail).result;
static if (isSame!(from, head))
alias result = TypeTuple!(to, next);
else
alias result = TypeTuple!(head, next);
}
else
{
alias result = TypeTuple!();
}
}
unittest
{
static assert(Pack!(ReplaceAll!(byte, ubyte,
byte, short, byte, byte)).
equals!(ubyte, short, ubyte, ubyte));
static assert(Pack!(ReplaceAll!(1111, byte,
1111, 2222, 1111, 1111)).
equals!(byte, 2222, byte, byte));
static assert(Pack!(ReplaceAll!(byte, 1111,
byte, short, byte, byte)).
equals!(1111, short, 1111, 1111));
static assert(Pack!(ReplaceAll!(1111, "11",
1111, 2222, 1111, 1111)).
equals!("11", 2222, "11", "11"));
}
/**
* Returns a typetuple created from TList with the order reversed.
*/
template Reverse(TList...)
{
static if (TList.length <= 1)
{
alias Reverse = TList;
}
else
{
alias Reverse =
TypeTuple!(
Reverse!(TList[$/2 .. $ ]),
Reverse!(TList[ 0 .. $/2]));
}
}
///
unittest
{
alias Types = TypeTuple!(int, long, long, int, float);
alias TL = Reverse!(Types);
static assert(is(TL == TypeTuple!(float, int, long, long, int)));
}
/**
* Returns the type from TList that is the most derived from type T.
* If none are found, T is returned.
*/
template MostDerived(T, TList...)
{
static if (TList.length == 0)
alias MostDerived = T;
else static if (is(TList[0] : T))
alias MostDerived = MostDerived!(TList[0], TList[1 .. $]);
else
alias MostDerived = MostDerived!(T, TList[1 .. $]);
}
///
unittest
{
class A { }
class B : A { }
class C : B { }
alias Types = TypeTuple!(A, C, B);
MostDerived!(Object, Types) x; // x is declared as type C
static assert(is(typeof(x) == C));
}
/**
* Returns the typetuple TList with the types sorted so that the most
* derived types come first.
*/
template DerivedToFront(TList...)
{
static if (TList.length == 0)
alias DerivedToFront = TList;
else
alias DerivedToFront =
TypeTuple!(MostDerived!(TList[0], TList[1 .. $]),
DerivedToFront!(ReplaceAll!(MostDerived!(TList[0], TList[1 .. $]),
TList[0],
TList[1 .. $])));
}
///
unittest
{
class A { }
class B : A { }
class C : B { }
alias Types = TypeTuple!(A, C, B);
alias TL = DerivedToFront!(Types);
static assert(is(TL == TypeTuple!(C, B, A)));
}
/**
Evaluates to $(D TypeTuple!(F!(T[0]), F!(T[1]), ..., F!(T[$ - 1]))).
*/
template staticMap(alias F, T...)
{
static if (T.length == 0)
{
alias staticMap = TypeTuple!();
}
else static if (T.length == 1)
{
alias staticMap = TypeTuple!(F!(T[0]));
}
else
{
alias staticMap =
TypeTuple!(
staticMap!(F, T[ 0 .. $/2]),
staticMap!(F, T[$/2 .. $ ]));
}
}
///
unittest
{
import std.traits : Unqual;
alias TL = staticMap!(Unqual, int, const int, immutable int);
static assert(is(TL == TypeTuple!(int, int, int)));
}
unittest
{
import std.traits : Unqual;
// empty
alias Empty = staticMap!(Unqual);
static assert(Empty.length == 0);
// single
alias Single = staticMap!(Unqual, const int);
static assert(is(Single == TypeTuple!int));
alias T = staticMap!(Unqual, int, const int, immutable int);
static assert(is(T == TypeTuple!(int, int, int)));
}
/**
Tests whether all given items satisfy a template predicate, i.e. evaluates to
$(D F!(T[0]) && F!(T[1]) && ... && F!(T[$ - 1])).
Evaluation is $(I not) short-circuited if a false result is encountered; the
template predicate must be instantiable with all the given items.
*/
template allSatisfy(alias F, T...)
{
static if (T.length == 0)
{
enum allSatisfy = true;
}
else static if (T.length == 1)
{
enum allSatisfy = F!(T[0]);
}
else
{
enum allSatisfy =
allSatisfy!(F, T[ 0 .. $/2]) &&
allSatisfy!(F, T[$/2 .. $ ]);
}
}
///
unittest
{
import std.traits : isIntegral;
static assert(!allSatisfy!(isIntegral, int, double));
static assert( allSatisfy!(isIntegral, int, long));
}
/**
Tests whether any given items satisfy a template predicate, i.e. evaluates to
$(D F!(T[0]) || F!(T[1]) || ... || F!(T[$ - 1])).
Evaluation is $(I not) short-circuited if a true result is encountered; the
template predicate must be instantiable with all the given items.
*/
template anySatisfy(alias F, T...)
{
static if(T.length == 0)
{
enum anySatisfy = false;
}
else static if (T.length == 1)
{
enum anySatisfy = F!(T[0]);
}
else
{
enum anySatisfy =
anySatisfy!(F, T[ 0 .. $/2]) ||
anySatisfy!(F, T[$/2 .. $ ]);
}
}
///
unittest
{
import std.traits : isIntegral;
static assert(!anySatisfy!(isIntegral, string, double));
static assert( anySatisfy!(isIntegral, int, double));
}
/**
* Filters a $(D TypeTuple) using a template predicate. Returns a
* $(D TypeTuple) of the elements which satisfy the predicate.
*/
template Filter(alias pred, TList...)
{
static if (TList.length == 0)
{
alias Filter = TypeTuple!();
}
else static if (TList.length == 1)
{
static if (pred!(TList[0]))
alias Filter = TypeTuple!(TList[0]);
else
alias Filter = TypeTuple!();
}
else
{
alias Filter =
TypeTuple!(
Filter!(pred, TList[ 0 .. $/2]),
Filter!(pred, TList[$/2 .. $ ]));
}
}
///
unittest
{
import std.traits : isNarrowString, isUnsigned;
alias Types1 = TypeTuple!(string, wstring, dchar[], char[], dstring, int);
alias TL1 = Filter!(isNarrowString, Types1);
static assert(is(TL1 == TypeTuple!(string, wstring, char[])));
alias Types2 = TypeTuple!(int, byte, ubyte, dstring, dchar, uint, ulong);
alias TL2 = Filter!(isUnsigned, Types2);
static assert(is(TL2 == TypeTuple!(ubyte, uint, ulong)));
}
unittest
{
import std.traits : isPointer;
static assert(is(Filter!(isPointer, int, void*, char[], int*) == TypeTuple!(void*, int*)));
static assert(is(Filter!isPointer == TypeTuple!()));
}
// Used in template predicate unit tests below.
private version (unittest)
{
template testAlways(T...)
{
enum testAlways = true;
}
template testNever(T...)
{
enum testNever = false;
}
template testError(T...)
{
static assert(false, "Should never be instantiated.");
}
}
/**
* Negates the passed template predicate.
*/
template templateNot(alias pred)
{
enum templateNot(T...) = !pred!T;
}
///
unittest
{
import std.traits : isPointer;
alias isNoPointer = templateNot!isPointer;
static assert(!isNoPointer!(int*));
static assert(allSatisfy!(isNoPointer, string, char, float));
}
unittest
{
foreach (T; TypeTuple!(int, staticMap, 42))
{
static assert(!Instantiate!(templateNot!testAlways, T));
static assert(Instantiate!(templateNot!testNever, T));
}
}
/**
* Combines several template predicates using logical AND, i.e. constructs a new
* predicate which evaluates to true for a given input T if and only if all of
* the passed predicates are true for T.
*
* The predicates are evaluated from left to right, aborting evaluation in a
* short-cut manner if a false result is encountered, in which case the latter
* instantiations do not need to compile.
*/
template templateAnd(Preds...)
{
template templateAnd(T...)
{
static if (Preds.length == 0)
{
enum templateAnd = true;
}
else
{
static if (Instantiate!(Preds[0], T))
alias templateAnd = Instantiate!(.templateAnd!(Preds[1 .. $]), T);
else
enum templateAnd = false;
}
}
}
///
unittest
{
import std.traits : isNumeric, isUnsigned;
alias storesNegativeNumbers = templateAnd!(isNumeric, templateNot!isUnsigned);
static assert(storesNegativeNumbers!int);
static assert(!storesNegativeNumbers!string && !storesNegativeNumbers!uint);
// An empty list of predicates always yields true.
alias alwaysTrue = templateAnd!();
static assert(alwaysTrue!int);
}
unittest
{
foreach (T; TypeTuple!(int, staticMap, 42))
{
static assert( Instantiate!(templateAnd!(), T));
static assert( Instantiate!(templateAnd!(testAlways), T));
static assert( Instantiate!(templateAnd!(testAlways, testAlways), T));
static assert(!Instantiate!(templateAnd!(testNever), T));
static assert(!Instantiate!(templateAnd!(testAlways, testNever), T));
static assert(!Instantiate!(templateAnd!(testNever, testAlways), T));
static assert(!Instantiate!(templateAnd!(testNever, testError), T));
static assert(!is(typeof(Instantiate!(templateAnd!(testAlways, testError), T))));
}
}
/**
* Combines several template predicates using logical OR, i.e. constructs a new
* predicate which evaluates to true for a given input T if and only at least
* one of the passed predicates is true for T.
*
* The predicates are evaluated from left to right, aborting evaluation in a
* short-cut manner if a true result is encountered, in which case the latter
* instantiations do not need to compile.
*/
template templateOr(Preds...)
{
template templateOr(T...)
{
static if (Preds.length == 0)
{
enum templateOr = false;
}
else
{
static if (Instantiate!(Preds[0], T))
enum templateOr = true;
else
alias templateOr = Instantiate!(.templateOr!(Preds[1 .. $]), T);
}
}
}
///
unittest
{
import std.traits : isPointer, isUnsigned;
alias isPtrOrUnsigned = templateOr!(isPointer, isUnsigned);
static assert( isPtrOrUnsigned!uint && isPtrOrUnsigned!(short*));
static assert(!isPtrOrUnsigned!int && !isPtrOrUnsigned!(string));
// An empty list of predicates never yields true.
alias alwaysFalse = templateOr!();
static assert(!alwaysFalse!int);
}
unittest
{
foreach (T; TypeTuple!(int, staticMap, 42))
{
static assert( Instantiate!(templateOr!(testAlways), T));
static assert( Instantiate!(templateOr!(testAlways, testAlways), T));
static assert( Instantiate!(templateOr!(testAlways, testNever), T));
static assert( Instantiate!(templateOr!(testNever, testAlways), T));
static assert(!Instantiate!(templateOr!(), T));
static assert(!Instantiate!(templateOr!(testNever), T));
static assert( Instantiate!(templateOr!(testAlways, testError), T));
static assert( Instantiate!(templateOr!(testNever, testAlways, testError), T));
// DMD @@BUG@@: Assertion fails for int, seems like a error gagging
// problem. The bug goes away when removing some of the other template
// instantiations in the module.
// static assert(!is(typeof(Instantiate!(templateOr!(testNever, testError), T))));
}
}
// : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : //
package:
/*
* With the builtin alias declaration, you cannot declare
* aliases of, for example, literal values. You can alias anything
* including literal values via this template.
*/
// symbols and literal values
template Alias(alias a)
{
static if (__traits(compiles, { alias x = a; }))
alias Alias = a;
else static if (__traits(compiles, { enum x = a; }))
enum Alias = a;
else
static assert(0, "Cannot alias " ~ a.stringof);
}
// types and tuples
template Alias(a...)
{
alias Alias = a;
}
unittest
{
enum abc = 1;
static assert(__traits(compiles, { alias a = Alias!(123); }));
static assert(__traits(compiles, { alias a = Alias!(abc); }));
static assert(__traits(compiles, { alias a = Alias!(int); }));
static assert(__traits(compiles, { alias a = Alias!(1,abc,int); }));
}
// : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : //
private:
/*
* [internal] Returns true if a and b are the same thing, or false if
* not. Both a and b can be types, literals, or symbols.
*
* How: When:
* is(a == b) - both are types
* a == b - both are literals (true literals, enums)
* __traits(isSame, a, b) - other cases (variables, functions,
* templates, etc.)
*/
private template isSame(ab...)
if (ab.length == 2)
{
static if (__traits(compiles, expectType!(ab[0]),
expectType!(ab[1])))
{
enum isSame = is(ab[0] == ab[1]);
}
else static if (!__traits(compiles, expectType!(ab[0])) &&
!__traits(compiles, expectType!(ab[1])) &&
__traits(compiles, expectBool!(ab[0] == ab[1])))
{
static if (!__traits(compiles, &ab[0]) ||
!__traits(compiles, &ab[1]))
enum isSame = (ab[0] == ab[1]);
else
enum isSame = __traits(isSame, ab[0], ab[1]);
}
else
{
enum isSame = __traits(isSame, ab[0], ab[1]);
}
}
private template expectType(T) {}
private template expectBool(bool b) {}
unittest
{
static assert( isSame!(int, int));
static assert(!isSame!(int, short));
enum a = 1, b = 1, c = 2, s = "a", t = "a";
static assert( isSame!(1, 1));
static assert( isSame!(a, 1));
static assert( isSame!(a, b));
static assert(!isSame!(b, c));
static assert( isSame!("a", "a"));
static assert( isSame!(s, "a"));
static assert( isSame!(s, t));
static assert(!isSame!(1, "1"));
static assert(!isSame!(a, "a"));
static assert( isSame!(isSame, isSame));
static assert(!isSame!(isSame, a));
static assert(!isSame!(byte, a));
static assert(!isSame!(short, isSame));
static assert(!isSame!(a, int));
static assert(!isSame!(long, isSame));
static immutable X = 1, Y = 1, Z = 2;
static assert( isSame!(X, X));
static assert(!isSame!(X, Y));
static assert(!isSame!(Y, Z));
int foo();
int bar();
real baz(int);
static assert( isSame!(foo, foo));
static assert(!isSame!(foo, bar));
static assert(!isSame!(bar, baz));
static assert( isSame!(baz, baz));
static assert(!isSame!(foo, 0));
int x, y;
real z;
static assert( isSame!(x, x));
static assert(!isSame!(x, y));
static assert(!isSame!(y, z));
static assert( isSame!(z, z));
static assert(!isSame!(x, 0));
}
/*
* [internal] Confines a tuple within a template.
*/
private template Pack(T...)
{
alias tuple = T;
// For convenience
template equals(U...)
{
static if (T.length == U.length)
{
static if (T.length == 0)
enum equals = true;
else
enum equals = isSame!(T[0], U[0]) &&
Pack!(T[1 .. $]).equals!(U[1 .. $]);
}
else
{
enum equals = false;
}
}
}
unittest
{
static assert( Pack!(1, int, "abc").equals!(1, int, "abc"));
static assert(!Pack!(1, int, "abc").equals!(1, int, "cba"));
}
/*
* Instantiates the given template with the given list of parameters.
*
* Used to work around syntactic limitations of D with regard to instantiating
* a template from a type tuple (e.g. T[0]!(...) is not valid) or a template
* returning another template (e.g. Foo!(Bar)!(Baz) is not allowed).
*/
// TODO: Consider publicly exposing this, maybe even if only for better
// understandability of error messages.
alias Instantiate(alias Template, Params...) = Template!Params;