Lists¶
The list type in the CAMP library is a powerful tool for type manipulation and
metaprogramming in C++. It allows you to create and operate on sequences of types
at compile time, enabling various operations such as accessing, filtering, and
transforming types.
Some important notes:
Note
All Camp structures and classes are within the namespace camp.
Introduction¶
In C++, templates provide a way to define functions and classes that operate on types.
The list type serves as a container for types, similar to how a standard container
holds values. This allows for advanced type-level programming, where you can perform
operations on types as if they were values.
The list type is defined as a variadic template, allowing you to store any number
of types. You can use it to create type sequences, manipulate them, and apply various
algorithms to them.
Common use cases for list include:
Storing a collection of types for type traits or type transformations.
Implementing compile-time algorithms that operate on types.
Creating type-safe interfaces or APIs that leverage type information.
Usage and Example Code¶
The list structure is literally just a struct with a variadic template:
template <typename... Ts>
struct list {
using type = list;
};
Thus, the list type is incredibly versatile as it can handle any number of types. Since list is just a structure with a single
member type, there are no methods that are directly part of list; however, Camp provides many helper methods that act on lists.
Here are some examples demonstrating how to use the list type and its associated functions.
The base list structure, the list-specific at construct, and the find_if contstruct are
all included in /include/list.hpp. All of the other helper methods described below are contained in
/include/camp.hpp.
Creating a List¶
You can create a list of types using the list template:
using MyList = camp::list<int, double, char>;
Alternatively, you can turn a different type into a list using the as_list construct:
using MyList = camp::as_list</*listable construct*/>
Accessing Types with at¶
To access a specific type in the list, use the at template:
using MyList = camp::list<int, double, char>;
using FirstType = camp::at<MyList, camp::num<0>>::type;
// FirstType is int
using SecondType = camp::at<MyList, camp::num<1>>::type;
// SecondType is double
using ThirdType = camp::at_v<MyList, 2>;
// thirdType is char
The at functionality also contains two convenience templates for accessing the first and second elements of a list (in a tuple-like manner):
using myList = camp::list<int, double, char>;
using firstType = camp::first<myList>;
// firstType is int
using secondType = camp::second<myList>;
// secondType is double
Finding a Type with find_if¶
You can find the first type in the list that satisfies a condition using find_if:
using myList = list<float, double, int*>;
using FoundType = camp::find_if<is_double, MyList>::type;
// FoundType is int*
If the condition in find_if cannot be met, it will return nil.
Combining Lists with extend , prepend, and append¶
You can combine two lists into one using either the extend method, prepend method, or append method. Like in python, extend
will add the elements of one list into the back of the other list. Prepend and append will both add the extra parameters to either
the front or back of an existing list, respectively. Let’s look at some examples:
// Extend
using list1 = camp::list<float, double, double>;
using list2 = camp::list<int, int, char>;
using list3 = camp::extend<list1, list2>::type;
// list3 is type camp::list<float, double, double, int, int, char>
// append
using list4 = camp::append<list1, list2>::type;
// list4 is type camp::list<float, double, double, list<int, int, char>>
// prepend
using list5 = camp::prepend<list1, list2>::type;
// list5 is type camp::list<list<int, int, char>, float, double, double>
Extend requires two lists to be given as inputs, whereas prepend and append can take any type:
using list1 = camp::list<int, int, char>;
using list2 = camp::append<list2, double>::type;
// list2 is type camp::list<int, int, char, double>
Flattening Nested Lists¶
Nested/multi dimensional lists can be flattened into a single dimension using the flatten construct.
using list1 = camp::list<int, list<char, double>, list<list<list<float>>>>;
using list2 = camp::flatten<list1>::type;
// list2 is of type list<int, char, double, float>;
Performing transformations on elements of a list¶
Camp provides a transform construct to perform operations on the types contained in a list:
using list1 = camp::list<int&, int&>;
using list2 = camp::transform<std::remove_reference, list1>;
// list2 is of type camp::list<int, int>;
Operating on lists with the Accumulate construct¶
The accumulate construct can be used to apply a given operation to a list. Accumulate
takes an operation, an initial value, and a list. It applies the operation across the list, starting with
the initial value.
using myNewList = accumulate<append, list<>, list<int, float, double>>;
// myNewList is of type list<int, float, double>;
Cartesian products of lists (an application of accumulate)¶
Camp provides a method to evaluate the cartesian product of two lists. The cartesian_product method is simply an
application of the accumulate method.
struct a;
struct b;
struct c;
struct d;
struct e;
using listA = list<a, b>;
using listB = list<c, d, e>
using prod = cartesian_product<listA, listB>;
// prod is of type list<list<a, c>,
// list<a, d>,
// list<a, e>,
// list<b, c>,
// list<b, d>,
// list<b, e>>
Finding the first index of a type within a list¶
The index_of method can be used on a list to find the first index in the list where
a given type appears. If the type is not found in a list, nil is returned.
using myList = list<int, double, char, float>
using firstChar = index_of<char, myList>::type
// fistChar is num<2>
using firstBool = index_of<bool, myList>::type
// firstBool is nil
Filtering Types with filter¶
Camp provides a way to filter a list such that only the desired types remain.
using myList = list<int, float*, double, short*>;
using ptrsOnly = filter<std::is_pointer, myList>;
// ptrsOnly is of type list<float*, short*>
Using Lists to make Maps¶
Camp provides a map.hpp header which can be combined with associative lists
to createa map-type structure. Consider the following:
using myMap = list<list<int, num<0>>, list<char, num<1>>>;
Using the at_key method, we can do a lookup on the maps “keys” to access its “values”. This works
because the lists act as key value pairs. Here is an example of a lookup using the at_key method:
using myMap = list<list<int, num<0>>, list<char, num<1>>>;
using val = at_key<myList, int>;
// val is num<0>