-
Notifications
You must be signed in to change notification settings - Fork 48
Introduction
Brigand is a header-only library.
To use it in your project you need but to specify the path to the brigand include directory, there is no linking step.
For convenience purposes we wrote a tool that assembles all the brigand include files into a single file. The Python script is available here.
Brigand requires a C++ 11 compiler, the list of supported compilers is available here.
A list of types has no runtime footprint and is your basic tool for most metaprogramming tasks. We provide you with a sequence named brigand::list
that supports all basic operations you expect from a sequence.
Let's start simple, with an empty list:
#include <brigand/sequences/list.hpp>
using empty_list = brigand::list<>;
We predefined for you an empty list for clarity: brigand::empty_sequence
.
We will now create a list of type that contains a bool, an integer and a pointer to a string of characters.
#include <brigand/sequences/list.hpp>
using my_list = brigand::list<bool, int, char *>;
Thanks to the usage of variadic templates, Brigand has no practical limit to the number of items in a list. There is also no restriction to the type that may go in a list, as long as it's properly defined. Gentlemen: start your compilers!
You can access the front and back element with convenience functions:
#include <brigand/sequences/list.hpp>
#include <brigand/sequences/back.hpp>
#include <brigand/sequences/front.hpp>
using my_list = brigand::list<bool, int, char *>;
// head is 'bool'
using head = brigand::front<my_list>;
// last is 'char *'
using last = brigand::back<my_list>;
Lists in Brigand also support efficient random access:
#include <brigand/sequences/list.hpp>
#include <brigand/sequences/at.hpp>
using my_list = brigand::list<bool, int, char *>;
// e1 is 'int'
using e1 = brigand::at<my_list, std::integral_constant<int, 1>>;
// you might want to use the convenience function at_c
using e1bis = brigand::at_c<my_list, 1>;
You may want to declare a list of types somewhere in your code, just to modify it later on. It's possible to add entries to the end and the beginning of a list.
We will add a char to the end of the list and another bool to the beginning.
#include <brigand/sequences/list.hpp>
#include <brigand/sequences/back.hpp>
#include <brigand/sequences/front.hpp>
using my_list = brigand::list<bool, int, char *>;
// somwhere else
using my_list2 = brigand::push_back<my_list, char>;
using my_list3 = brigand::push_front<my_list2, bool>;
The resulting list will be bool, bool, int, char *, char
.
It's important to understand that in template metaprogramming, types are never updated in place. A meta function will return the result of your operation that you may want to "save" in another type.
You could also write:
using my_list2 = brigand::push_front<brigand::push_back<my_list, char>, bool>;
You may also remove elements at the beginning and the end of a list:
#include <brigand/sequences/list.hpp>
#include <brigand/sequences/back.hpp>
#include <brigand/sequences/front.hpp>
using my_list = brigand::list<bool, int, char *>;
// my_list2 is int, char *
using my_list2 = brigand::pop_front<my_list>;
// my_list 3 is int
using my_list3 = brigand::pop_back<my_list2>;
All these meta functions support multiple parameters, you can therefore write:
#include <brigand/sequences/list.hpp>
#include <brigand/sequences/back.hpp>
#include <brigand/sequences/front.hpp>
using my_list = brigand::list<bool, int, char *>;
// my_list2 is 'bool, int, char*, short, long'
using my_list2 = brigand::push_back<my_list, short, long>;
// my_list3 is 'bool, int, char *'
using my_list3 = brigand::pop_back<my_list2, std::integral_constant<int, 2>>;
If you have two lists, don't do complex manipulations!
There is a meta function perfectly suited for the job:
#include <brigand/sequences/list.hpp>
#include <brigand/sequences/append.hpp>
struct proton {};
struct neutron {};
using deuterium = brigand::list<proton, neutron>;
using tritium = brigand::list<proton, neutron, neutron>;
// omg will contain 'proton, neutron, proton, neutron, neutron'
using omg = brigand::append<deuterium, tritium>;
You may find list of types to have limited usage in themselves, we will see later more advanced manipulations. However, you may right away transform your list into a tuple.
#include <brigand/sequences/list.hpp>
#include <brigand/adapted/tuple.hpp>
#include <string>
using my_list = brigand::list<bool, int, std::string>;
using my_tuple = brigand::as_tuple<my_list>;
// t is std::tuple<bool, int, std::string>
my_tuple t;
Combined with the possibility to add (and remove) types from a list, this enable you to create and validate the list of types that go in a tuple at compile time.
Brigand also supports other types such as Boost.Variant:
#include <brigand/sequences/list.hpp>
#include <brigand/adapted/variant.hpp>
#include <string>
using my_list = brigand::list<bool, int, std::string>;
using my_variant = brigand::as_variant<my_list>;
// v is boost::variant<bool, int, std::string>
my_variant v;
One of the greatest strength of Brigand is that it works on list of types. We give you the brigand::list
but anything which is a list of types will work with our meta functions and algorithms...
...and this story shall also be told.