// Pattern Matching of Variadic Templates for Type Collections in C++ // - see peano.cpp for an introduction to type arithmetic // - check a functional programming language like Haskell for // the declaration and usage of recursive lists // compile and test: "c++ typecollections.cpp -o typecollections && ./typecollections" // // typelist declaration // template struct typelist { }; // // typelist_index: get the (first) index of a type // // empty declaration: compilation error if the type is not found template struct typelist_index { }; // end of the recursion, the type match the head template struct typelist_index> { enum : unsigned { value = 0 }; }; // recursive declaration template struct typelist_index> { enum : unsigned { value = typelist_index>::value + 1u }; }; // // typelist_get: get the type at the given index // // empty declaration: compilation error if the index is out of bound template struct typelist_get { }; // end of the recursion, the type match template struct typelist_get<0u, typelist<_type, tail...>> { using type = _type; }; // recursive declaration template struct typelist_get> { using type = typename typelist_get>::type; }; // // typelist_insert: insert an element at the beginning of a list // // declaration template struct typelist_insert { }; // insert the new head, actually not recursive template struct typelist_insert> { using type = typelist; }; // // typedict_entry declaration // // typedict_entry declaration template struct typedict_entry { }; // // typedict_contains: check if the typelist contains the key // // declaration and fallback if the key is missing template struct typedict_contains { enum : bool { value = false }; }; // end of the recursion when the key is found template struct typedict_contains, tail...>> { enum : bool { value = true }; }; // recursive declaration template struct typedict_contains> { enum : bool { value = typedict_contains>::value }; }; // // typedict_index: get the (first) index of a key // // empty declaration: compilation error if the key is missing template struct typedict_index { }; // end of the recursion, the key match template struct typedict_index, tail...>> { enum : unsigned { value = 0 }; }; // recursive declaration template struct typedict_index> { enum : unsigned { value = typedict_index>::value + 1u }; }; // // typedict_get: get the type associated with a key // // empty declaration: compilation error if the key is missing template struct typedict_get { }; // end of the recursion: the key match a typedict_entry in the list template struct typedict_get, tail...>> { using type = _type; }; // recursive declaration template struct typedict_get> { using type = typename typedict_get>::type; }; // // typetree_flatten: flatten a tree // // empty declaration: end of the recursion if the typelist is empty template struct typetree_flatten { using type = typelist<>; }; // recursive declaration when the first element is a list template struct typetree_flatten, tail...>> { using type = typename typetree_flatten>::type; }; // recursive declaration template struct typetree_flatten> { using type = typename typelist_insert>::type>::type; }; // // now let's test! // #include void test_typelist() { using testlist = typelist; // output: index of bool = 0 printf("index of bool = %u\n", typelist_index::value); // output: index of int = 1 printf("index of int = %u\n", typelist_index::value); // output: index of float = 2 printf("index of float = %u\n", typelist_index::value); // compilation error: type not found // printf("index of double = %u\n", // typelist_index::value); auto const bool_value = typelist_get<0u, testlist>::type(true); auto const int_value = typelist_get<1u, testlist>::type(42); auto const float_value = typelist_get<2u, testlist>::type(3.14159f); // compilation error: cast not allowed // auto const badtype_value = typelist_get<2u, testlist>::type("string"); // compilation error: index out of range // auto const outofrange_value = typelist_get<3u, testlist>::type(); // output: bool = true, int = 42, float = 3.141590 printf("bool = %s, int = %d, float = %f\n", bool_value ? "true" : "false", int_value, float_value); } void test_typedict() { enum { key1, key2, key3, key4 }; using testdict = typelist< typedict_entry, typedict_entry, typedict_entry >; // output: contains key1 = true printf("contains key1 = %s\n", typedict_contains::value ? "true" : "false"); // output: contains key4 = false printf("contains key4 = %s\n", typedict_contains::value ? "true" : "false"); // output: index of key1 = 0 printf("index of key1 = %u\n", typedict_index::value); // output: index of key2 = 1 printf("index of key2 = %u\n", typedict_index::value); // output: index of key3 = 2 printf("index of key3 = %u\n", typedict_index::value); // compilation error: entry not found // printf("index of key4 = %u\n", // typedict_index::value); auto const bool_value = typedict_get::type(true); auto const int_value = typedict_get::type(42); auto const float_value = typedict_get::type(3.14159f); // compilation error: cast not allowed // auto const badtype_value = typedict_get::type("string"); // compilation error: entry not found // auto const outofrange_value = typedict_get::type(); // output: bool = true, int = 42, float = 3.141590 printf("bool = %s, int = %d, float = %f\n", bool_value ? "true" : "false", int_value, float_value); } void test_typetree() { enum { key1, key2, key3, key4 }; using testtree = typelist< typelist< typedict_entry >, typelist< typelist< typedict_entry > >, typelist< typelist< typelist< typedict_entry >, typedict_entry > > >; using flattened = typetree_flatten::type; // output: index of key1 = 0 printf("index of key1 = %u\n", typedict_index::value); // output: index of key2 = 1 printf("index of key2 = %u\n", typedict_index::value); // output: index of key3 = 2 printf("index of key3 = %u\n", typedict_index::value); // output: index of key4 = 3 printf("index of key4 = %u\n", typedict_index::value); } int main () { printf("\n> typelist test:\n"); test_typelist(); printf("\n> typedict test:\n"); test_typedict(); printf("\n> typetree test:\n"); test_typetree(); return 0; }