SpECTRE  v2022.05.05
Metaprogramming with Brigand

Note
This document covers Brigand as of commit 66b3d9276ed95425ac919ac1841286d088b5f4b1 in January 2022.
In SpECTRE, most complex TMP is done using the Brigand metaprogramming library. Brigand is a collection of templated classes, type aliases, and functions, primarily intended to help with the manipulation and use of lists of types. This document is organized to roughly parallel the structure of the C++ standard, rather than following Brigand's classifications.
Brigand provides all of its functionality in the brigand namespace, but in SpECTRE we have aliased this namespace to tmpl, and the latter should be preferred.
All functionality described here is provided by SpECTRE's Brigand wrapper header:
#include "Utilities/TMPL.hpp"
Examples in this document use the following declarations and definitions:
struct Type1;
struct Type2;
struct Type3;
// Sequence containers. Practical applications will usually use
// tmpl::list in place of these.
template <typename...>
struct List1;
template <typename...>
struct List2;
template <typename...>
struct List3;
template <typename>
struct Wrapper;
template <typename... T>
struct lazy_make_list1 {
using type = List1<T...>;
};
// A comparator on the above types defining Type1 < Type2 < Type3
using CompareType123 = tmpl::and_<tmpl::or_<std::is_same<tmpl::_1, Type1>,
tmpl::not_<std::is_same<tmpl::_1, tmpl::_2>>>;

Metafunctions

A metafunction is an analog of a familiar C++ function that is coded in the C++ type system. It turns out that, using metafunction programming, it is possible to perform arbitrary computations at compile time.
There are multiple ways to encode a calculation in the type system. When using Brigand, the relevant ones are eager and lazy metafunctions.

Eager and lazy metafunctions

Metafunctions commonly appear in two forms: eager and lazy. Lazy metafunctions are templated structs (or templated aliases to structs) with a type member alias that indicates the result:
template <typename T>
struct lazy_make_list_of_T_and_int {
using type = List1<T, int>;
};
The type traits in the standard library, such as std::is_same, are lazy metafunctions.
Eager metafunctions are aliases to their result types. As a trivial case, struct templates can be viewed as eager metafunctions returning themselves. An eager version of the previous example could be implemented as:
template <typename T>
using eager_make_list_of_T_and_int = List1<T, int>;
The standard library provides eager versions of some of its metafunctions (generally those that modify a type, rather than predicates) using an _t suffix. When both versions are provided, it is often convenient (and less error prone!) to define the eager version in terms of the lazy version:
template <typename T>
using eager_make_list_of_T_and_int2 =
typename lazy_make_list_of_T_and_int<T>::type;
And the two definitions agree:
assert_same<eager_make_list_of_T_and_int<double>,
eager_make_list_of_T_and_int2<double>>();
Note
The standard library also provides versions of many of its type traits with an _v suffix. These evaluate to compile-time values, rather than types. They can be useful for metaprogramming, but are not the types of metafunctions being discussed here.
Eager metafunctions are usually more convenient to use, so what is the point of additionally creating lazy ones? The answer is that lazy metafunctions can be used as compile-time functors. As a simple example, we can write an (eager) metafunction that calls an arbitrary lazy metafunction twice
template <typename Func, typename... Args>
struct apply_lazy_metafunction;
template <template <typename...> typename Func, typename... DummyArgs,
typename... Args>
struct apply_lazy_metafunction<Func<DummyArgs...>, Args...> {
using type = typename Func<Args...>::type;
};
template <typename Func>
using call_lazy_metafunction_twice =
List1<typename apply_lazy_metafunction<Func, double>::type,
typename apply_lazy_metafunction<Func, char>::type>;
and get the expected output:
struct Dummy;
assert_same<call_lazy_metafunction_twice<lazy_make_list_of_T_and_int<Dummy>>,
List1<List1<double, int>, List1<char, int>>>();
But it fails if you try to call an arbitrary eager metafunction twice in the same way, because the function is evaluated too early, resulting in the List1 metafunction being acted upon instead of eager_add_list:
template <typename Func, typename... Args>
struct apply_eager_metafunction;
template <template <typename...> typename Func, typename... DummyArgs,
typename... Args>
struct apply_eager_metafunction<Func<DummyArgs...>, Args...> {
using type = Func<Args...>;
};
template <typename Func>
using call_eager_metafunction_twice =
List1<typename apply_eager_metafunction<Func, double>::type,
typename apply_eager_metafunction<Func, char>::type>;
assert_same<call_eager_metafunction_twice<eager_make_list_of_T_and_int<Dummy>>,
List1<List1<double>, List1<char>>>();
(In this simple case we could have used a template template parameter to pass the eager metafunction in a form more similar to a runtime lambda, but the possibilities for generic manipulation of parameter lists containing template template parameters are limited, so their use must be minimized in complex metaprogramming.)
Note
In practice, lazy metafunctions are often implemented as empty structs inheriting from other lazy metafunctions. The entire inheritance chain then inherits a type alias from the ultimate base class.
Most of the standard Brigand functions are eager, but many have lazy versions in the nested tmpl::lazy namespace. These are indicated by calls to the HAS_LAZY_VERSION macro in the examples below.

Brigand metalambdas

This use of lazy metafunctions is too limited for general use, however, because it requires the definition of a new templated struct for every new function. Brigand uses a more general notation, known as metalambdas. A metalambda is a (possibly nested set of) lazy metafunctions with some template arguments replaced by the placeholders tmpl::_1, tmpl::_2, etc. These are the first, second, etc., arguments of the metalambda, and will be replaced by the actual arguments when the lambda is used. The lazy nature of the metafunctions prevents them from prematurely evaluating to results based on the literal placeholder types. The tmpl::apply function can be used to evaluate a metalambda with specified arguments, and many other Brigand functions take metalambdas that are evaluated internally.

Evaluation of metalambdas

Note
None of the terminology introduced in this section is standard.
When evaluating a metalambda, the values of any arguments encountered are taken from the evaluation's argument stack. The argument stack is a stack (in the CS sense) of collections of zero or more arguments. The values of any arguments that are evaluated are taken from the collection at the head of the stack. The remaining collections are arguments captures in closures, and will not be present in code not using tmpl::defer.
The tmpl::apply metafunction is the Brigand metafunction for evaluating metalambdas. It can be called explicitly, and is called internally by many other functions. It takes a metalambda and arguments to be passed to that metalambda. The argument stack for the evaluation has one entry: the passed arguments.
The argument stack can gain additional entries through the creation of metaclosures using tmpl::defer. When tmpl::defer is evaluated, it produces a metaclosure containing a copy of the current argument stack, acting as the lambda captures. When that metaclosure is evaluated, the previously active stack is replaced by the stored stack with the head of the old stack pushed onto it.
This makes arguments in a metaclosure refer to the arguments "passed" to it. (No explicit call syntax is used, but the arguments are inherited from the calling context.) The captured arguments are accessible using tmpl::parent, which pops off the last entry in the argument stack.
There are eight forms that a metalambda can take: an argument, a lazy expression, a bind expression, a pin expression, a defer expression, a parent expression, a constant, or a metaclosure.

Argument

An argument is one of the structs tmpl::_1, tmpl::_2, or tmpl::args<n> for unsigned int n. The additional aliases tmpl::_3, tmpl::_4, ..., tmpl::_9 are provided to tmpl::args<2>, tmpl::args<3>, ..., tmpl::args<8>. (The first two arguments have dedicated types in addition to the general tmpl::args<0> and tmpl::args<1>. My best guess is for performance reasons.)
static_assert(not std::is_same_v<tmpl::_1, tmpl::args<0>>);
static_assert(not std::is_same_v<tmpl::_2, tmpl::args<1>>);
static_assert(std::is_same_v<tmpl::_3, tmpl::args<2>>);
static_assert(std::is_same_v<tmpl::_4, tmpl::args<3>>);
When evaluated, they give the first (tmpl::_1), second (tmpl::_2), or zero-indexed Nth (tmpl::args<N>) entry from the collection of arguments at the top of the argument stack.
assert_same<tmpl::apply<tmpl::_1, Type1, Type2>, Type1>();
assert_same<tmpl::apply<tmpl::_2, Type1, Type2>, Type2>();
assert_same<tmpl::apply<tmpl::args<0>, Type1, Type2>, Type1>();
Additionally, tmpl::_state and tmpl::_element are aliased to tmpl::_1 and tmpl::_2, primarily for use with tmpl::fold.
When evaluating a metalambdas, the metalambda must be passed enough arguments to define all argument placeholders in its body. When evaluating using tmpl::apply, arguments are passed as template parameters after the metalambda. Other Brigand functions that evaluate metalambdas pass them a specified number of arguments (usually 1 or 2). Failure to pass enough arguments may error or produce unintuitive results.

Lazy expression

A lazy expression is a fully-specialized struct template with only type template parameters that is not a specialization of tmpl::pin, tmpl::defer, or tmpl::parent and is not a metaclosure. When evaluated, each of its template parameters is evaluated as a metalambda and replaced by the result, and then the struct's type type alias is the result of the full lazy-expression.
assert_same<tmpl::apply<lazy_make_list1<tmpl::_1, tmpl::_2>, Type1, Type2>,
List1<Type1, Type2>>();

Bind expression

A bind expression is a specialization of tmpl::bind. It wraps an eager metafunction and its arguments. When evaluated, the arguments are each evaluated as metalambdas, and then the results are passed to the eager metafunction.
assert_same<tmpl::apply<tmpl::bind<List1, tmpl::_1, tmpl::_2>, Type1, Type2>,
List1<Type1, Type2>>();
Note
The tmpl::bind metafunction does not convert an eager metafunction to a lazy one. It is handled specially in the evaluation code.

Pin expression

A pin expression is a specialization of tmpl::pin. Evaluating a pin expression gives the (unevaluated) argument to tmpl::pin. This can be used to force a type to be treated as a constant, even if it would normally be treated as a different type of metalambda (usually a lazy expression).
assert_same<tmpl::apply<tmpl::pin<List1<Type1>>>, List1<Type1>>();
// Error: List1 is not a lazy metafunction
// assert_same<tmpl::apply<List1<Type1>>, List1<Type1>>();
assert_same<tmpl::apply<tmpl::pin<tmpl::_1>, Type1>, tmpl::_1>();
Pin expressions are often used to protect template arguments to eager metafunctions:
template <typename T>
using is_int = tmpl::apply<std::is_same<tmpl::pin<T>, int>>;
static_assert(is_int<int>::value);
// Breaks without tmpl::pin: tmpl::list<> has no ::type
static_assert(not is_int<tmpl::list<>>::value);
constexpr T & value(T &t)
Returns t.value() if t is a std::optional otherwise returns t.
Definition: OptionalHelpers.hpp:32

Defer expression

A defer expression is a specialization of tmpl::defer. It does not evaluate its argument, but results in a metaclosure containing the passed metalambda and the current argument stack.
Example:
assert_same<
tmpl::apply<tmpl::apply<tmpl::defer<tmpl::_1>,
Type1>,
Type2>,
Type2>();
The evaluation here proceeds as follows:
  1. The innermost eager metafunction is the second tmpl::apply. It creates an argument stack with one collection containing the single argument Type1 and proceeds to evaluate tmpl::defer<tmpl::_1>.
  2. Evaluating the defer expression creates a metaclosure with the contents tmpl::_1 and the argument stack from the first apply. This is the result of the inner tmpl::apply.
  3. Next the outer tmpl::apply is evaluated. It creates an argument stack with one collection containing the single argumentType2, and proceeds to evaluate the metaclosure created above.
  4. Evaluating the metaclosure (see that section below) evaluates the contained tmpl::_1 with a two-element argument stack: head to tail [(Type2), (Type1)].
  5. The first (and only) argument (tmpl::_1) in the head of the argument stack is Type2, which is the result of the metaclosure and the entire expression.
The primary purposes for tmpl::defer are constructing metalambdas to pass to other metafunctions and preventing "speculative" evaluation of a portion of a metalambda that is not valid for some arguments. See the examples below, in particular make_subtracter, multiplication_table, maybe_first, and column_with_zeros.

Parent expression

A parent expression is a specialization of tmpl::parent. It evaluates its argument (treated as a metalambda) after popping the top entry off the argument stack. This provides access to the captured arguments in a metaclosure.
Example:
assert_same<
tmpl::apply<tmpl::apply<tmpl::defer<tmpl::parent<tmpl::_1>>,
Type1>,
Type2>,
Type1>();
The creation of the metaclosure here is similar to the example for tmpl::defer, except that the contained metalambda is tmpl::parent<tmpl::_1> instead of a plain tmpl::_1. The evaluation proceeds as:
  1. As in tmpl::defer example.
  2. As in tmpl::defer example.
  3. As in tmpl::defer example.
  4. The metaclosure evaluates the contained tmpl::parent<tmpl::_1> with the argument stack [(Type2), (Type1)].
  5. Evaluating the tmpl::parent pops the stack, and so evaluates tmpl::_1 with the stack [(Type1)].
  6. The first (and only) argument (tmpl::_1) in the stack's head is now Type1, which is the result of the metaclosure and the entire expression.
Warning
Do not call tmpl::parent when the argument stack is empty, i.e., do not attempt to access more sets of captured arguments than have been captured. If you want to prevent evaluation of an expression, use tmpl::pin.

Constant

A constant metalambda is any type that is not a struct template with only type template parameters, a specialization of tmpl::bind, or a metaclosure. A constant metalambda evaluates to itself.
assert_same<tmpl::apply<Type1>, Type1>();

Metaclosure

A metaclosure is an opaque type produced by tmpl::defer, containing a metalambda and an argument stack. When a metaclosure is evaluated, it evaluates the packaged metalambda with an argument stack constructed by pushing the head of the current argument stack onto the argument stack stored in the metaclosure. See Defer expression and Parent expression for examples.

Examples

evens

Finds all numbers in a list that are even.
template <typename L>
using evens = tmpl::filter<
L, tmpl::equal_to<tmpl::modulo<tmpl::_1, tmpl::integral_constant<int, 2>>,
tmpl::integral_constant<int, 0>>>;
assert_same<evens<tmpl::integral_list<int, 1, 1, 2, 3, 5, 8, 13>>,
tmpl::integral_list<int, 2, 8>>();
The tmpl::filter metafunction takes a metalambda as its second argument. The tmpl::integral_constants have non-type template parameters, so they are treated as constant expressions. The tmpl::equal_to and tmpl::modulo metafunctions are lazy, despite not being in the tmpl::lazy namespace.

maybe_first

Returns the first element of a list, or tmpl::no_such_type_ if the list is empty.
template <typename L>
using maybe_first = tmpl::apply<tmpl::apply<
tmpl::if_<tmpl::size<L>,
tmpl::defer<tmpl::bind<tmpl::front, tmpl::pin<L>>>,
tmpl::no_such_type_>>>;
auto apply(F &&f, const ObservationBox< ComputeTagsList, DataBoxType > &observation_box, Args &&... args)
Apply the function object f using its nested argument_tags list of tags.
Definition: ObservationBox.hpp:171
assert_same<maybe_first<tmpl::list<Type1>>, Type1>();
assert_same<maybe_first<tmpl::list<Type1, Type2>>, Type1>();
assert_same<maybe_first<tmpl::list<>>, tmpl::no_such_type_>();
In this example, the inner tmpl::apply call evaluates the tmpl::if_ statement, returning either a metaclosure or tmpl::no_such_type_. The outer tmpl::apply either evaluates the metaclosure, calling tmpl::front, or evaluates tmpl::no_such_type_, which is a constant and gives itself.
The reason for creating a metaclosure is that all the arguments to tmpl::if_ are always evaluated (it is an ordinary metafunction with no special treatment during evaluation). This is a problem, because, in a naive attempt at this metafunction, if L is an empty list tmpl::front<tmpl::list<>> would be evaluated for the first branch. To avoid this we use tmpl::defer to wrap the call to tmpl::front in a metaclosure, which we evaluate only if necessary.
Note that this metaclosure does not capture anything. L is substituted according to normal C++ rules before any Brigand evaluation. This means that the contents of the tmpl::defer are, for the first call above, tmpl::bind<tmpl::front, tmpl::pin<tmpl::list<Type1>>>. Without the tmpl::pin, the list would be interpreted as a lazy metafunction, resulting in an error because it does not have a type type alias.
The L in tmpl::size<L> does not need to be protected by a tmpl::pin because tmpl::size is an eager metafunction, so that expression has been converted to a tmpl::integral_constant before the metalambda evaluation starts.

factorial

Calculates the factorial using a simple metalambda passed to a tmpl::fold.
template <typename N>
using factorial =
tmpl::fold<tmpl::range<typename N::value_type, 1, N::value + 1>,
tmpl::integral_constant<typename N::value_type, 1>,
tmpl::times<tmpl::_state, tmpl::_element>>;
constexpr uint64_t factorial(const uint64_t n)
Compute the factorial of .
Definition: ConstantExpressions.hpp:88
assert_same<factorial<tmpl::size_t<5>>, tmpl::size_t<120>>();
A nearly literal rewrite of this into runtime C++ is
size_t factorial_cpp(const size_t n) {
std::iota(range.begin(), range.end(), 1);
size_t state = 1;
for (size_t i : range) {
state = state * i;
}
return state;
}
constexpr void iota(ForwardIterator first, ForwardIterator last, T value)
Definition: Numeric.hpp:20
The equivalent of a range-based for loop is easier to express in functional programming (as a fold) than a standard counting for loop.

make_subtracter

Demonstrates the use of captures in metalambdas.
template <typename N>
using make_subtracter =
tmpl::apply<tmpl::defer<tmpl::minus<tmpl::_1, tmpl::parent<tmpl::_1>>>, N>;
using subtract_three = make_subtracter<tmpl::size_t<3>>;
assert_same<tmpl::apply<subtract_three, tmpl::size_t<5>>, tmpl::size_t<2>>();
This metafunction returns a metaclosure that subtracts a given number from it's argument. That metaclosure uses both the argument passed to it (tmpl::_1, which is 5 in the example) and the value captured at it's creation (tmpl::parent<tmpl::_1>, which is 3 in the example).
(This make_subtracter could be implemented more simply as
template <typename N>
using make_subtracter_simple = tmpl::minus<tmpl::_1, tmpl::pin<N>>;
but that doesn't demonstrate metaclosures.)

multiplication_table

Constructs a multiplication table.
template <typename N>
using multiplication_table =
tmpl::transform<
tmpl::range<typename N::value_type, 1, N::value + 1>,
tmpl::lazy::transform<
tmpl::pin<tmpl::range<typename N::value_type, 1, N::value + 1>>,
tmpl::defer<tmpl::times<tmpl::_1, tmpl::parent<tmpl::_1>>>>>;
assert_same<multiplication_table<tmpl::size_t<5>>,
tmpl::list<tmpl::integral_list<size_t, 1, 2, 3, 4, 5>,
tmpl::integral_list<size_t, 2, 4, 6, 8, 10>,
tmpl::integral_list<size_t, 3, 6, 9, 12, 15>,
tmpl::integral_list<size_t, 4, 8, 12, 16, 20>,
tmpl::integral_list<size_t, 5, 10, 15, 20, 25>>>();
This demonstrates the use of tmpl::defer to pass a closure as an argument to a metafunction (tmpl::lazy::transform), while capturing an argument from the outer context (the metalambda evaluated for the outer tmpl::transform). This is the use most similar to common uses of the C++ lambda.
The outer (eager) tmpl::transform evaluates its second argument as a metalambda. This first evaluates the arguments to the inner tmpl::lazy::transform. The first argument is a tmpl::list of tmpl::integral_constants (because the tmpl::range is eager and has already been evaluated). This must be protected by a tmpl::pin because it looks like a lazy metafunction. The second argument gives a metaclosure, capturing the value from the outer tmpl::transform (available as tmpl::parent<tmpl::_1>). The tmpl::list (without the tmpl::pin, which has already been evaluated) and metaclosure are then passed to the inner tmpl::lazy::transform.

column_with_zeros

Extracts a column from a row-major matrix, extending any short rows with zeros.
template <typename Lists, typename Column>
using column_with_zeros =
tmpl::transform<
Lists,
tmpl::bind<
tmpl::if_<
tmpl::greater<tmpl::bind<tmpl::size, tmpl::_1>, Column>,
tmpl::defer< // avoid out-of-range call to `at`
tmpl::parent<
tmpl::bind<tmpl::at, tmpl::_1, Column>>>,
tmpl::size_t<0>>>>;
assert_same<
column_with_zeros<
tmpl::list<tmpl::integral_list<size_t, 11, 12, 13>,
tmpl::integral_list<size_t, 21, 22, 23, 24, 25>,
tmpl::integral_list<size_t, 31, 32, 33, 34>>,
tmpl::size_t<3>>,
tmpl::integral_list<size_t, 0, 24, 34>>();
This example shows another use of tmpl::defer to avoid evaluating an invalid expression, similar to maybe_first. The use of an argument in the deferred branch makes this case more complicated: a tmpl::parent expression is used to access arguments from where the tmpl::defer occurs to avoid having to pass the argument explicitly using the tmpl::apply call.
This is the "apply-defer-parent" pattern for lazy evaluation. A tmpl::parent is placed immediately inside a tmpl::defer with a (not immediately) surrounding tmpl::apply. The tmpl::apply and tmpl::defer collectively add an (empty) element to the head of the argument stack, which is then popped off to restore the original value. This causes the interior metalambda to have the same result it would have had without the tmpl::defer.

factorial_recursion

Again calculates the factorial, but using a recursive algorithm.
template <typename N>
using factorial_recursion =
tmpl::bind<tmpl::apply, tmpl::_1, tmpl::_1, N>,
tmpl::bind< // recursive metalambda starts here
tmpl::if_<
tmpl::_2, // base case: zero is false
tmpl::defer< // prevent speculative recursion
tmpl::parent<
tmpl::times<
tmpl::_2,
tmpl::bind<tmpl::apply, tmpl::_1,
tmpl::_1, tmpl::prev<tmpl::_2>>>>>,
tmpl::integral_constant<typename N::value_type, 1>>>>;
assert_same<factorial_recursion<tmpl::size_t<5>>, tmpl::size_t<120>>();
This is a direct translation of the common definition \(f(N) = N f(N-1)\) for nonzero \(N\), and \(f(0) = 1\). The metalambda is passed a copy of itself as the first argument and the value to take the factorial of as the second.
This again uses the "apply-defer-parent" pattern to prevent "speculative" evaluation of conditional branches. In this example, speculative evaluation of the branch is invalid because it would recurse infinitely.

primes

Generates a list of prime numbers less than N using the sieve of Eratosthenes. This example defines three helper metafunctions. Two, zero and replace_at, are defined only for clarity's sake and could be inlined. The third, range_from_types, is not easily inlinable, and works around Brigand's lack of sequence generating functions without non-type template parameters.
template <typename N>
using zero = tmpl::integral_constant<typename N::value_type, 0>;
// Return Sequence with the Nth element replaced by NewType.
template <typename Sequence, typename N, typename NewType>
using replace_at =
tmpl::append<tmpl::front<tmpl::split_at<Sequence, N>>,
tmpl::list<NewType>,
tmpl::pop_front<tmpl::back<tmpl::split_at<Sequence, N>>>>;
template <typename Start, typename End>
using range_from_types =
tmpl::range<typename Start::value_type, Start::value, End::value>;
template <typename N>
using primes =
tmpl::remove<
tmpl::fold<
tmpl::range<typename N::value_type, 2, N::value>,
tmpl::range<typename N::value_type, 2, N::value>, zero<N>, zero<N>>,
tmpl::bind<
tmpl::if_< // Skip work for known-composite entries
tmpl::or_<
tmpl::bind<tmpl::at, tmpl::_state, tmpl::_element>, zero<N>>,
// Only iteration up to sqrt(N) is necessary
tmpl::greater_equal<
tmpl::times<tmpl::_element, tmpl::_element>, N>>,
tmpl::defer< // Match other branch (don't execute the state)
tmpl::parent<tmpl::_state>>,
tmpl::defer<
tmpl::parent<
tmpl::lazy::fold<
tmpl::bind<
range_from_types,
tmpl::_element,
tmpl::next<tmpl::divides<tmpl::prev<N>, tmpl::_element>>>,
tmpl::_state,
tmpl::defer< // Passed as a closure to the inner fold
tmpl::bind<
tmpl::_state,
tmpl::times<tmpl::parent<tmpl::_element>, tmpl::_element>,
zero<N>>>>>>>>>,
zero<N>>;
CoordinateMap< SourceFrame, TargetFrame, NewMap, Maps... > push_front(CoordinateMap< SourceFrame, TargetFrame, Maps... > old_map, NewMap new_map)
Creates a CoordinateMap by prepending the new map to the beginning of the old maps.
constexpr std::array< std::decay_t< T >, Size > replace_at(const std::array< T, Size > &arr, T value)
Replace at compile time the Ith entry in the array with value
Definition: ConstantExpressions.hpp:365
assert_same<
primes<tmpl::size_t<100>>,
tmpl::integral_list<size_t, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97>>();
This is roughly equivalent to the following C++ code with loops converted fo fold expressions over ranges.
std::vector<size_t> primes_cpp(const size_t n) {
std::vector<size_t> sieve(n, 0);
std::iota(sieve.begin() + 2, sieve.end(), 2);
for (size_t i = 2; i < n; ++i) {
if (not (sieve[i] == 0 or i * i >= n)) {
for (size_t j = i; j < (n - 1) / i + 1; ++j) {
sieve[i * j] = 0;
}
}
}
std::copy_if(sieve.begin(), sieve.end(),
std::insert_iterator(result, result.begin()),
[](const size_t x) { return x != 0; });
return result;
}

Guidelines for writing metafunctions

This section covers a few general guidelines for writing metafunctions in SpECTRE. Some of the Brigand functions mentioned below have specific advice as well.
  1. For general metafunctions, write both lazy and eager versions. Follow the STL convention of foo being lazy, foo_t being eager, and foo_v being a constexpr value (if applicable). This does not apply to internal-use or special-purpose metafunctions.
    template <typename T>
    struct always_true : std::true_type {};
    template <typename T>
    using always_true_t = typename always_true<T>::type;
    template <typename T>
    constexpr bool always_true_v = always_true<T>::value;
  2. Don't perform unnecessary return-type conversions. We often recommend using STL types over equivalent Brigand types, but if the implementation naturally produces a Brigand type do not do extra work to convert it.

Brigand types and functions

In this section, CamelCase identifiers indicate type template parameters or, occasionally, template template parameters. Identifiers in all lowercase indicate non-type template parameters. Identifiers in [brackets] are optional, and the default value will be identified in the prose description. Identifiers with ellipses... represent zero or more parameters.
The head of a fully specialized class template is the class template itself (e.g., the head of tmpl::list<T, U, V> is tmpl::list). When taken as a metafunction parameter, these are template template parameters and are usually called Head below.
An identifier called Sequence must be a full specialization of a class template with no non-type template parameters. Many functions do not make sense on sequences with a fixed length, and these require the head of their sequence arguments to take a variable number of template arguments. In practical applications, sequence arguments will usually be specializations of tmpl::list.
Parameters called Predicate must be unary metalambdas returning tmpl::integral_constants of bool or compatible classes.
Parameters called Comparator must be binary metalambdas returning tmpl::integral_constants of bool or compatible classes. They must establish a strict weak ordering on the types they will be applied to in the same manner as runtime comparators from the STL.
Metafunctions documented here are eager unless otherwise noted. In many cases, Brigand provides lazy versions of its metafunctions under the same name in the tmpl::lazy namespace. These cases are indicated by the presence of the HAS_LAZY_VERSION macro in the usage example.

Containers

Brigand provides container classes with the sole purpose of wrapping other things.

integral_constant<T, value>

A compile-time value value of type T. Very similar to std::integral_constant, except that the constexpr specifiers on the member functions have been omitted.
using T = tmpl::integral_constant<int, 3>;
assert_same<T::value_type, int>();
assert_same<T::type, T>();
static_assert(T::value == 3);
// At runtime only
CHECK(T{} == 3);
CHECK(T{}() == 3);
Brigand supplies type aliases for constants of some specific types:
assert_same<tmpl::int8_t<3>, tmpl::integral_constant<int8_t, 3>>();
assert_same<tmpl::int16_t<3>, tmpl::integral_constant<int16_t, 3>>();
assert_same<tmpl::int32_t<3>, tmpl::integral_constant<int32_t, 3>>();
assert_same<tmpl::int64_t<3>, tmpl::integral_constant<int64_t, 3>>();
assert_same<tmpl::uint8_t<3>, tmpl::integral_constant<uint8_t, 3>>();
assert_same<tmpl::uint16_t<3>, tmpl::integral_constant<uint16_t, 3>>();
assert_same<tmpl::uint32_t<3>, tmpl::integral_constant<uint32_t, 3>>();
assert_same<tmpl::uint64_t<3>, tmpl::integral_constant<uint64_t, 3>>();
assert_same<tmpl::size_t<3>, tmpl::integral_constant<size_t, 3>>();
assert_same<tmpl::ptrdiff_t<3>, tmpl::integral_constant<ptrdiff_t, 3>>();
assert_same<tmpl::bool_<true>, tmpl::integral_constant<bool, true>>();
Most metafunctions that accept integral_constants will accept any type with a value static member variable.
Because of the type type alias, integral_constants behave like lazy metafunctions returning themselves. Most lazy metafunctions producing an integral_constant will actually inherit from their result, so value will be directly available without needing to go through the type alias.
Remarks
Prefer std::integral_constant, except for the convenience wrapper tmpl::size_t or when necessary for type equality comparison.

list<T...>

An empty struct templated on a parameter pack, with no additional functionality.
static_assert(not std::is_same_v<tmpl::list<Type1, Type2>,
tmpl::list<Type2, Type1>>);
Most metafunctions that operate on lists will work on any struct template.

map<Pair...>

A collection of key-value tmpl::pairs with unique keys. See the section on operations on maps for details.
assert_same<tmpl::lookup<tmpl::map<tmpl::pair<Type1, int>,
tmpl::pair<Type2, double>>,
Type1>,
int>();
The actual type of a map is unspecified, but it has the same template parameters as a call to map that would produce it.
Warning
Equivalent maps may have different types, depending on the order their keys are stored in internally.

pair<T1, T2>

A pair of types, with easy access to each type in the pair.
assert_same<tmpl::pair<Type1, Type2>::first_type, Type1>();
assert_same<tmpl::pair<Type1, Type2>::second_type, Type2>();

set<T...>

An unordered collection of distinct types. Trying to create a set with duplicate entries is an error (but tmpl::insert ignores duplicate entries). See the section on operations on sets for details.
assert_same<tmpl::contains<tmpl::set<Type1, Type2>, Type1>, tmpl::true_type>();
The actual type of a set is unspecified, but it has the same template parameters as a call to set that would produce it.
Warning
Equivalent sets may have different types, depending on the order their elements are stored in internally.

type_<T>

A struct containing a type alias to T.
assert_same<tmpl::type_<Type1>::type, Type1>();
When extracting the type, programmers are encouraged to use tmpl::type_from to make it clear that the ::type that would otherwise appear is not an evaluation of a lazy metafunction. See tmpl::always or tmpl::identity for similar functionality that is intended for use as a metafunction.

Constants

Brigand defines a few concrete types and type aliases.

empty_base

An empty struct used by tmpl::inherit and tmpl::inherit_linearly. Primarily for internal use.
assert_same<tmpl::inherit_linearly<List1<>, List2<>>, tmpl::empty_base>();

empty_sequence

An empty tmpl::list.
assert_same<tmpl::empty_sequence, tmpl::list<>>();
Remarks
Prefer just writing tmpl::list<>.

false_type

A tmpl::integral_constant representing false. Similar to std::false_type.
assert_same<tmpl::false_type, tmpl::bool_<false>>();
Remarks
Prefer std::false_type.

no_such_type_

An empty struct returned as the failure case for various searching operations.
assert_same<tmpl::index_of<List1<>, Type1>, tmpl::no_such_type_>();

true_type

A tmpl::integral_constant representing true. Similar to std::true_type.
assert_same<tmpl::true_type, tmpl::bool_<true>>();
Remarks
Prefer std::true_type.

Constructor-like functions for lists

These functions produce tmpl::lists from non-list values. They are often similar to constructors in the STL.

filled_list<Entry, n, [Head]>

Creates a list containing n (passed as an unsigned int) of Entry. The head of the list defaults to tmpl::list.
assert_same<tmpl::filled_list<Type1, 3, List1>, List1<Type1, Type1, Type1>>();
assert_same<tmpl::filled_list<Type1, 3>, tmpl::list<Type1, Type1, Type1>>();

integral_list<T, n...>

Shorthand for a tmpl::list of tmpl::integral_constants of the type T with values n....
assert_same<tmpl::integral_list<int, 3, 2, 1>,
tmpl::list<tmpl::integral_constant<int, 3>,
tmpl::integral_constant<int, 2>,
tmpl::integral_constant<int, 1>>>();
Remarks
Prefer std::integer_sequence when used for pack expansion. Prefer tmpl::integral_list when the contents need to be manipulated for more complicated metaprogramming.

make_sequence<Start, n, [Next], [Head]>

Produces a list with first element Start and length n (provided as an unsigned int). The remaining elements are obtained by repeated applications of the metalambda Next, defaulting to tmpl::next. The head of the sequence can be specified, and defaults to tmpl::list.
assert_same<tmpl::make_sequence<tmpl::size_t<5>, 3>,
tmpl::list<tmpl::size_t<5>, tmpl::size_t<6>, tmpl::size_t<7>>>();
assert_same<tmpl::make_sequence<Type1, 3, lazy_make_list1<tmpl::_1>, List2>,
List2<Type1, List1<Type1>, List1<List1<Type1>>>>();
See also
tmpl::range, tmpl::repeat

range<T, start, stop>

Produces a tmpl::list of tmpl::integral_constants of type T representing adjacent ascending integers from start to stop, including the starting value and excluding the ending value.
assert_same<tmpl::range<size_t, 4, 7>,
tmpl::list<tmpl::size_t<4>, tmpl::size_t<5>, tmpl::size_t<6>>>();
assert_same<tmpl::range<size_t, 4, 4>, tmpl::list<>>();
See also
tmpl::reverse_range

reverse_range<T, start, stop>

Produces a tmpl::list of tmpl::integral_constants of type T representing adjacent descending integers from start to stop, including the starting value and excluding the ending value.
assert_same<tmpl::reverse_range<size_t, 7, 4>,
tmpl::list<tmpl::size_t<7>, tmpl::size_t<6>, tmpl::size_t<5>>>();
assert_same<tmpl::reverse_range<size_t, 7, 7>, tmpl::list<>>();
See also
tmpl::range

Functions for querying lists

These tend to be similar to const member functions in the STL and the non-modifying sequence operations in <algorithm>. They are most frequently used with tmpl::list, but similar classes will also work.

all<Sequence, [Predicate]>

Checks if Predicate is true for all elements of Sequence. The default predicate checks that the element's value is not equal to zero.
assert_same<tmpl::all<List1<tmpl::size_t<0>, tmpl::size_t<1>, tmpl::size_t<2>>>,
tmpl::false_type>();
assert_same<tmpl::all<List1<tmpl::size_t<1>, tmpl::size_t<1>, tmpl::size_t<2>>>,
tmpl::true_type>();
assert_same<tmpl::all<List1<tmpl::size_t<0>, tmpl::size_t<1>, tmpl::size_t<2>>,
tmpl::less<tmpl::_1, tmpl::size_t<2>>>,
tmpl::false_type>();
assert_same<tmpl::all<List1<tmpl::size_t<0>, tmpl::size_t<1>, tmpl::size_t<0>>,
tmpl::less<tmpl::_1, tmpl::size_t<2>>>,
tmpl::true_type>();
assert_same<tmpl::all<List1<>>, tmpl::true_type>();
Note
The predicate must return the same true value for each element for all to return true.
assert_same<tmpl::all<List1<std::true_type, tmpl::true_type>, tmpl::_1>,
tmpl::false_type>();
See also
tmpl::any, tmpl::none

any<Sequence, [Predicate]>

Checks if Predicate is true for at least one element of Sequence. The default predicate checks that the element's value is not equal to zero.
assert_same<tmpl::any<List1<tmpl::size_t<0>, tmpl::size_t<1>, tmpl::size_t<2>>>,
tmpl::true_type>();
assert_same<tmpl::any<List1<tmpl::size_t<0>, tmpl::size_t<0>, tmpl::size_t<0>>>,
tmpl::false_type>();
assert_same<tmpl::any<List1<tmpl::size_t<0>, tmpl::size_t<1>, tmpl::size_t<2>>,
tmpl::less<tmpl::_1, tmpl::size_t<2>>>,
tmpl::true_type>();
assert_same<tmpl::any<List1<tmpl::size_t<4>, tmpl::size_t<3>, tmpl::size_t<2>>,
tmpl::less<tmpl::_1, tmpl::size_t<2>>>,
tmpl::false_type>();
assert_same<tmpl::any<List1<>>, tmpl::false_type>();
Remarks
The tmpl::any and tmpl::none metafunctions perform the same tasks as tmpl::found and tmpl::not_found, but use different algorithms. In general, tmpl::any and tmpl::none are much faster, but tmpl::found and tmpl::not_found short-circuit, so they may be preferable with short lists and expensive predicates.
Note
The predicate must return the same false value for each element for any to return false.
assert_same<tmpl::any<List1<std::false_type, tmpl::false_type>, tmpl::_1>,
tmpl::true_type>();
See also
tmpl::all, tmpl::found, tmpl::none

at<Sequence, Index>

Retrieves a given element of Sequence, similar to operator[] of the STL containers. The Index is supplied as a tmpl::integral_constant or similar type.
assert_same<tmpl::at<List1<Type1, Type2, Type3>, tmpl::size_t<0>>, Type1>();
This operator is overloaded for maps.
See also
tmpl::at_c

at_c<Sequence, n>

Retrieves a given element of Sequence, similar to operator[] of the STL containers. The index n is supplied as an unsigned int.
assert_same<tmpl::at_c<List1<Type1, Type2, Type3>, 0>, Type1>();
See also
tmpl::at

back<Sequence>

Retrieves the last element of Sequence.
assert_same<tmpl::back<List1<Type1, Type2, Type3>>, Type3>();

count_if<Sequence, Predicate>

Returns the number of elements of Sequence satisfying Predicate.
assert_same<tmpl::count_if<List1<Type1, Type2, Type1>,
tmpl::integral_constant<size_t, 2>>();

fold<Sequence, State, Functor>

Performs a left fold, i.e., given a list Sequence, initial state State, and metalambda Functor, updates the state by calling Functor on the state and the first element of Sequence, repeats with the second, and so on, returning the final state.
assert_same<tmpl::fold<List2<Type1, Type2>, Type3,
lazy_make_list1<tmpl::_state, tmpl::_element>>,
List1<List1<Type3, Type1>, Type2>>();
HAS_LAZY_VERSION(fold);
Brigand provides tmpl::_state and tmpl::_element aliases to the appropriate arguments for use in folds.
See also
tmpl::reverse_fold

found<Sequence, [Predicate]>

Returns, as a tmpl::integral_constant of bool, whether Predicate matches any element of Sequence. The default predicate checks that the element's value is not equal to zero.
assert_same<
tmpl::found<List1<Type1, Type2, Type2, Type3>, std::is_same<tmpl::_1, Type2>>,
tmpl::true_type>();
assert_same<
tmpl::found<List1<Type1, Type1, Type1, Type3>, std::is_same<tmpl::_1, Type2>>,
tmpl::false_type>();
assert_same<
tmpl::found<List1<tmpl::size_t<0>, tmpl::size_t<1>, tmpl::size_t<2>>>,
tmpl::true_type>();
Remarks
This function performs the same operation as tmpl::any. See tmpl::any for discussion.
See also
tmpl::any, tmpl::find, tmpl::not_found

front<Sequence>

Retrieves the first element of Sequence.
assert_same<tmpl::front<List1<Type1, Type2, Type3>>, Type1>();

Finds the index as a size_t tmpl::integral_constant of the first type in Sequence satisfying Predicate. Returns NotFound, defaulting to tmpl::no_such_type_ if no elements match.
assert_same<tmpl::index_if<List1<Type1, Type2, Type3>,
tmpl::size_t<2>>();
assert_same<tmpl::index_if<List1<Type1, Type3, Type3>,
tmpl::size_t<1>>();
assert_same<tmpl::index_if<List1<Type1>, std::is_same<Type3, tmpl::_1>>,
tmpl::no_such_type_>();
assert_same<tmpl::index_if<List1<Type1>, std::is_same<Type3, tmpl::_1>, Type2>,
Type2>();

index_of<Sequence, T>

Finds the index as a size_t tmpl::integral_constant of the first occurrence of T in Sequence. Returns tmpl::no_such_type_ if the type is not found.
assert_same<tmpl::index_of<List1<Type1, Type2, Type3>, Type3>,
tmpl::size_t<2>>();
assert_same<tmpl::index_of<List1<Type1, Type3, Type3>, Type3>,
tmpl::size_t<1>>();
assert_same<tmpl::index_of<List1<Type1>, Type2>,
tmpl::no_such_type_>();

list_contains<Sequence, T>

Checks whether T is contained in Sequence, returning a tmpl::integral_constant of bool.
assert_same<tmpl::list_contains<List1<Type1, Type2>, Type1>, tmpl::true_type>();
static_assert(tmpl::list_contains_v<List1<Type1, Type2>, Type1>);
static_assert(not tmpl::list_contains_v<List1<Type2, Type2>, Type1>);
Note
This is not a Brigand metafunction. It is implemented in SpECTRE.

none<Sequence, [Predicate]>

Checks if Predicate is false for all elements of Sequence. The default predicate checks that the element's value is not equal to zero.
assert_same<
tmpl::none<List1<tmpl::size_t<0>, tmpl::size_t<1>, tmpl::size_t<2>>>,
tmpl::false_type>();
assert_same<
tmpl::none<List1<tmpl::size_t<0>, tmpl::size_t<0>, tmpl::size_t<0>>>,
tmpl::true_type>();
assert_same<
tmpl::none<List1<tmpl::size_t<0>, tmpl::size_t<1>, tmpl::size_t<2>>,
tmpl::less<tmpl::_1, tmpl::size_t<2>>>,
tmpl::false_type>();
assert_same<
tmpl::none<List1<tmpl::size_t<4>, tmpl::size_t<3>, tmpl::size_t<2>>,
tmpl::less<tmpl::_1, tmpl::size_t<2>>>,
tmpl::true_type>();
assert_same<tmpl::none<List1<>>, tmpl::true_type>();
Remarks
This function performs the same operation as tmpl::not_found. See tmpl::any for discussion.
Note
The predicate must return the same false value for each element for none to return true.
assert_same<tmpl::none<List1<std::false_type, tmpl::false_type>, tmpl::_1>,
tmpl::false_type>();
See also
tmpl::all, tmpl::any, tmpl::not_found

not_found<Sequence, [Predicate]>

Returns, as a tmpl::integral_constant of bool, whether Predicate matches no elements of Sequence. The default predicate checks that the element's value is not equal to zero.
assert_same<
tmpl::not_found<List1<Type1, Type2, Type2, Type3>,
tmpl::false_type>();
assert_same<
tmpl::not_found<List1<Type1, Type1, Type1, Type3>,
tmpl::true_type>();
assert_same<
tmpl::not_found<List1<tmpl::size_t<0>, tmpl::size_t<1>, tmpl::size_t<2>>>,
tmpl::false_type>();
Remarks
This function performs the same operation as tmpl::none. See tmpl::any for discussion.
See also
tmpl::find, tmpl::found, tmpl::none

size<Sequence>

Returns the number of elements in Sequence as a tmpl::integral_constant of type unsigned int.
assert_same<tmpl::size<List1<Type1, Type1>>,
tmpl::integral_constant<unsigned int, 2>>();
See also
tmpl::count

Functions producing lists from other lists

These tend to be similar to non-const member functions in the STL and the mutating sequence operations in <algorithm>, but due to the nature of metaprogramming all return a new list rather than modifying an argument. They are most frequently used with tmpl::list, but similar classes will also work.

append<Sequence...>

Concatenates all of its arguments, keeping the head of the first (or tmpl::list if passed no arguments).
assert_same<tmpl::append<List1<Type1, Type2>, List2<>, List2<Type2>>,
List1<Type1, Type2, Type2>>();
assert_same<tmpl::append<>, tmpl::list<>>();
HAS_LAZY_VERSION(append);
See also
tmpl::join

clear<Sequence>

Produces a list with the same head as Sequence but no elements.
assert_same<tmpl::clear<List1<Type1>>, List1<>>();
Remarks
If the head is known, prefer writing it explicitly. If the head is irrelevant, write an empty tmpl::list.

erase<Sequence, Index>

Produces a copy of Sequence with the element at index Index (passed as a tmpl::integral_constant or similar type) removed.
assert_same<tmpl::erase<List1<Type1, Type2, Type3>, tmpl::size_t<1>>,
List1<Type1, Type3>>();
This operator is overloaded for maps and for sets.
See also
erase_c<Sequence, n>

erase_c<Sequence, n>

Produces a copy of Sequence with the element at index n (passed as an unsigned int) removed.
assert_same<tmpl::erase_c<List1<Type1, Type2, Type3>, 1>,
List1<Type1, Type3>>();

filter<Sequence, Predicate>

Removes all types not matching Predicate from Sequence.
assert_same<tmpl::filter<List1<Type1, Type2, Type1, Type3>,
List1<Type1, Type1>>();
HAS_LAZY_VERSION(filter);
See also
tmpl::remove_if

find<Sequence, [Predicate]>

Returns a list containing the first element of Sequence for which Predicate returns true and all subsequent elements. The default predicate checks that the element's value is not equal to zero. Returns an empty list if the predicate returns false for all elements.
assert_same<
tmpl::find<List1<Type1, Type2, Type2, Type3>, std::is_same<tmpl::_1, Type2>>,
List1<Type2, Type2, Type3>>();
assert_same<
tmpl::find<List1<Type1, Type1, Type1, Type3>, std::is_same<tmpl::_1, Type2>>,
List1<>>();
assert_same<
tmpl::find<List1<tmpl::size_t<0>, tmpl::size_t<1>, tmpl::size_t<2>>>,
List1<tmpl::size_t<1>, tmpl::size_t<2>>>();
HAS_LAZY_VERSION(find);
constexpr InputIt find(InputIt first, InputIt last, const T &value)
Definition: Algorithm.hpp:136
See also
tmpl::found, tmpl::not_found, tmpl::reverse_find

flatten<Sequence>

Recursively inlines the contents of elements of Sequence that are sequences with the same head.
assert_same<
tmpl::flatten<List1<List1<Type1, List1<Type2>>, List2<List1<Type3>>>>,
List1<Type1, Type2, List2<List1<Type3>>>>();
HAS_LAZY_VERSION(flatten);
See also
tmpl::join

join<Sequence>

Combines lists in the same manner as tmpl::append, but takes a list of lists instead of multiple arguments.
assert_same<tmpl::join<List3<List1<Type1, Type2>, List2<>, List2<Type2>>>,
List1<Type1, Type2, Type2>>();
assert_same<tmpl::join<List1<>>, tmpl::list<>>();
HAS_LAZY_VERSION(join);

list_difference<Sequence1, Sequence2>

Remove all elements that occur in Sequence2 from Sequence1.
assert_same<tmpl::list_difference<List1<Type1, Type2, Type1, Type2>,
List2<Type3, Type2>>,
List1<Type1, Type1>>();
Note
This is not a Brigand metafunction. It is implemented in SpECTRE.

merge<Sequence1, Sequence2, [Comparator]>

Given two sorted lists, returns a sorted list containing the elements of both. A comparator metalambda can be provided, defaulting to tmpl::less.
assert_same<
tmpl::merge<List1<tmpl::size_t<1>, tmpl::size_t<2>, tmpl::size_t<5>>,
List2<tmpl::size_t<1>, tmpl::size_t<3>, tmpl::size_t<6>>>,
List1<tmpl::size_t<1>, tmpl::size_t<1>, tmpl::size_t<2>, tmpl::size_t<3>,
tmpl::size_t<5>, tmpl::size_t<6>>>();
assert_same<tmpl::merge<List1<Type1, Type2>, List2<Type1, Type3>,
CompareType123>,
List1<Type1, Type1, Type2, Type3>>();
Note
If there are equivalent elements, those from the second list are placed earlier.
assert_same<tmpl::merge<List1<Type1, Type1>, List2<Type2, Type2>,
List1<Type2, Type2, Type1, Type1>>();
See also
std::merge

partition<Sequence, Predicate>

Returns a tmpl::pair containing a list of the elements of Sequence for which the Predicate returns true and a list of the elements of Sequence for which the Predicate returns false.
assert_same<tmpl::partition<List1<Type1, Type2, Type1, Type3>,
tmpl::pair<List1<Type1, Type1>, List1<Type2, Type3>>>();
See also
tmpl::filter, tmpl::remove_if

pop_back<Sequence, [Count]>

Remove Count elements from the end of Sequence. The number of elements to remove is supplied as a tmpl::integral_constant and defaults to 1.
assert_same<tmpl::pop_back<List1<Type1, Type2, Type3>>, List1<Type1, Type2>>();
assert_same<tmpl::pop_back<List1<Type1, Type2, Type3>,
tmpl::integral_constant<unsigned int, 2>>,
List1<Type1>>();

pop_front<Sequence, [Count]>

Remove Count elements from the beginning of Sequence. The number of elements to remove is supplied as a tmpl::integral_constant and defaults to 1.
assert_same<tmpl::pop_front<List1<Type1, Type2, Type3>>,
List1<Type2, Type3>>();
assert_same<tmpl::pop_front<List1<Type1, Type2, Type3>,
tmpl::integral_constant<unsigned int, 2>>,
List1<Type3>>();
HAS_LAZY_VERSION(pop_front);

push_back<Sequence, T...>

Appends types T... to Sequence.
assert_same<tmpl::push_back<List1<Type1>, Type2, Type3>,
List1<Type1, Type2, Type3>>();

push_front<Sequence, T...>

Prepends types T... to Sequence. The order of the prepended items is retained: they are pushed as a unit, not one-by-one.
assert_same<tmpl::push_front<List1<Type1>, Type2, Type3>,
List1<Type2, Type3, Type1>>();
HAS_LAZY_VERSION(push_front);

remove<Sequence, T>

Removes all occurrences of T from Sequence.
assert_same<tmpl::remove<List1<Type1, Type2, Type1, Type3>, Type1>,
List1<Type2, Type3>>();
HAS_LAZY_VERSION(remove);

remove_duplicates<Sequence>

Remove duplicates from Sequence. The first occurrence of each type is kept.
assert_same<tmpl::remove_duplicates<List1<Type1, Type2, Type1, Type3, Type2>>,
List1<Type1, Type2, Type3>>();
Note
This is not a Brigand metafunction. It is implemented in SpECTRE.

remove_if<Sequence, Predicate>

Removes all types matching Predicate from Sequence.
assert_same<tmpl::remove_if<List1<Type1, Type2, Type1, Type3>,
List1<Type2, Type3>>();
HAS_LAZY_VERSION(remove_if);
See also
tmpl::filter

replace<Sequence, Old, New>

Replaces all occurrences of Old in Sequence with New.
assert_same<tmpl::replace<List1<Type1, Type2, Type1>, Type1, Type3>,
List1<Type3, Type2, Type3>>();
HAS_LAZY_VERSION(replace);

replace_if<Sequence, Predicate, T>

Replaces all types in Sequence matching Predicate with T.
assert_same<tmpl::replace_if<List1<Type1, Type2, Type1>,
List1<Type3, Type2, Type3>>();
HAS_LAZY_VERSION(replace_if);

reverse<Sequence>

Reverses the order of types in Sequence.
assert_same<tmpl::reverse<List1<Type1, Type2, Type3, Type1>>,
List1<Type1, Type3, Type2, Type1>>();
HAS_LAZY_VERSION(reverse);
constexpr void reverse(BidirectionalIterator first, BidirectionalIterator last)
Definition: Algorithm.hpp:79

reverse_find<Sequence, [Predicate]>

Returns a list containing the last element of Sequence for which Predicate returns true and all preceding elements. The default predicate checks that the element's value is not equal to zero. Returns an empty list if the predicate returns false for all elements.
assert_same<
tmpl::reverse_find<List1<Type1, Type2, Type2, Type3>,
List1<Type1, Type2, Type2>>();
assert_same<
tmpl::reverse_find<List1<Type1, Type1, Type1, Type3>,
List1<>>();
assert_same<
tmpl::reverse_find<List1<tmpl::size_t<0>, tmpl::size_t<1>, tmpl::size_t<2>>>,
List1<tmpl::size_t<0>, tmpl::size_t<1>, tmpl::size_t<2>>>();
HAS_LAZY_VERSION(reverse_find);
See also
tmpl::find

reverse_fold<Sequence, State, Functor>

Performs a right fold, i.e., given a list Sequence, initial state State, and metalambda Functor, updates the state by calling Functor on the state and the last element of Sequence, repeats with the second to last, and so on, returning the final state.
assert_same<tmpl::reverse_fold<List2<Type1, Type2>, Type3,
lazy_make_list1<tmpl::_state, tmpl::_element>>,
List1<List1<Type3, Type2>, Type1>>();
HAS_LAZY_VERSION(reverse_fold);
Brigand provides tmpl::_state and tmpl::_element aliases to the appropriate arguments for use in folds.
See also
tmpl::fold

sort<Sequence, [Comparator]>

Sorts Sequence according to Comparator, which defaults to tmpl::less.
assert_same<tmpl::sort<List1<tmpl::size_t<9>, tmpl::size_t<6>,
tmpl::size_t<7>, tmpl::size_t<0>>>,
List1<tmpl::size_t<0>, tmpl::size_t<6>, tmpl::size_t<7>,
tmpl::size_t<9>>>();
assert_same<tmpl::sort<List1<Type2, Type3, Type3, Type1, Type2, Type3, Type2>,
CompareType123>,
List1<Type1, Type2, Type2, Type2, Type3, Type3, Type3>>();
Note
The sort is not stable.
assert_same<tmpl::sort<List1<Type1, Type2, Type3>, std::false_type>,
List1<Type3, Type2, Type1>>();

split<Sequence, Delimiter>

Splits Sequence into parts separated by Delimiter, discarding empty parts.
assert_same<
tmpl::split<List1<Type1, Type2, Type3, Type2, Type3, Type3, Type1>, Type3>,
List1<List1<Type1, Type2>, List1<Type2>, List1<Type1>>>();
HAS_LAZY_VERSION(split);

split_at<Sequence, Index>

Returns a list of two of lists, the first containing the first Index (supplied as a tmpl::integral_constant) elements or Sequence, and the second containing the remaining elements.
assert_same<tmpl::split_at<List1<Type1, Type2, Type3>,
tmpl::integral_constant<unsigned int, 2>>,
List1<List1<Type1, Type2>, List1<Type3>>>();
HAS_LAZY_VERSION(split_at);

transform<Sequence, Sequences..., Functor>

Calls a Functor on each element of Sequence, collecting the results in a new list. If additional Sequences... are supplied, elements from those lists are passed as additional arguments to Functor.
assert_same<
tmpl::transform<List2<Type1, Type2, Type3>, List3<Type3, Type2, Type1>,
lazy_make_list1<tmpl::_1, tmpl::_2>>,
List2<List1<Type1, Type3>, List1<Type2, Type2>, List1<Type3, Type1>>>();
HAS_LAZY_VERSION(transform);
Holds functions related to transforming between frames.
Definition: Transform.hpp:17

Operations on maps

Brigand's tmpl::map type can be manipulated by several metafunctions.
Examples in this section use this map as an example:
using example_map =
tmpl::map<tmpl::pair<Type1, int>, tmpl::pair<Type2, double>>;

at<Map, Key>

Returns the value associated with Key in Map. Returns tmpl::no_such_type_ if Key is not in the map.
assert_same<tmpl::at<example_map, Type1>, int>();
assert_same<tmpl::at<example_map, Type3>, tmpl::no_such_type_>();
This operator is overloaded for lists. When called on a tmpl::map, this is the same as tmpl::lookup.

erase<Map, Key>

Produces a copy of Map with the element with the key Key removed. If Key is not in the map, returns Map unchanged.
assert_maps_same<tmpl::erase<example_map, Type1>,
tmpl::map<tmpl::pair<Type2, double>>>();
assert_maps_same<tmpl::erase<example_map, Type3>, example_map>();
This operator is overloaded for lists and for sets.

has_key<Map, Key>

Returns a tmpl::integral_constant of bool indicating whether Map contains the key Key.
assert_same<tmpl::has_key<example_map, Type2>, tmpl::true_type>();
assert_same<tmpl::has_key<example_map, Type3>, tmpl::false_type>();
This operator is overloaded for sets.

insert<Map, Pair>

Returns Map with Pair added. If the key of Pair is already in the map, the map is returned unchanged.
assert_maps_same<tmpl::insert<example_map, tmpl::pair<Type3, int>>,
tmpl::map<tmpl::pair<Type1, int>, tmpl::pair<Type2, double>,
tmpl::pair<Type3, int>>>();
assert_maps_same<tmpl::insert<example_map, tmpl::pair<Type1, float>>,
example_map>();
This operator is overloaded for sets.

keys_as_sequence<Map, [Head]>

Returns the keys from Map as a sequence with head Head, defaulting to tmpl::set.
assert_sets_same<tmpl::keys_as_sequence<example_map>,
tmpl::set<Type1, Type2>>();
static_assert(std::is_same_v<tmpl::keys_as_sequence<example_map, List1>,
List1<Type1, Type2>> or
std::is_same_v<tmpl::keys_as_sequence<example_map, List1>,
List1<Type2, Type1>>);
If the key-value pairs are required, they can be extracted directly from the template arguments of the tmpl::map.
See also
tmpl::values_as_sequence

lookup<Map, Key>

Returns the value associated with Key in Map. Returns tmpl::no_such_type_ if Key is not in the map.
assert_same<tmpl::lookup<example_map, Type1>, int>();
assert_same<tmpl::lookup<example_map, Type3>, tmpl::no_such_type_>();
HAS_LAZY_VERSION(lookup);
See also
tmpl::at

lookup_at<Map, Key>

Returns the value associated with Key in Map, wrapped in a tmpl::type_. Returns type_<no_such_type_> if Key is not in the map. This function has no eager version, but is still in the tmpl::lazy namespace.
assert_same<tmpl::lazy::lookup_at<example_map, Type1>::type,
tmpl::type_<int>>();
assert_same<tmpl::lazy::lookup_at<example_map, Type3>::type,
tmpl::type_<tmpl::no_such_type_>>();
See also
tmpl::lookup

values_as_sequence<Map, [Head]>

Returns the values from Map as a sequence with head Head, defaulting to tmpl::list.
static_assert(std::is_same_v<tmpl::values_as_sequence<example_map>,
tmpl::list<int, double>> or
std::is_same_v<tmpl::values_as_sequence<example_map>,
tmpl::list<double, int>>);
static_assert(std::is_same_v<tmpl::values_as_sequence<example_map, List1>,
List1<int, double>> or
std::is_same_v<tmpl::values_as_sequence<example_map, List1>,
List1<double, int>>);
If the key-value pairs are required, they can be extracted directly from the template arguments of the tmpl::map.
See also
tmpl::keys_as_sequence

Operations on sets

Brigand's tmpl::set type can be manipulated by several metafunctions.

contains<Set, T>

Returns a tmpl::integral_constant of bool indicating whether Set contains T.
assert_same<tmpl::contains<tmpl::set<Type1, Type2>, Type1>, tmpl::true_type>();
assert_same<tmpl::contains<tmpl::set<Type1, Type2>, Type3>, tmpl::false_type>();

erase<Set, T>

Produces a copy of Set with the element T removed. If the element is not in the set, returns the set unchanged.
assert_sets_same<tmpl::erase<tmpl::set<Type1, Type2>, Type1>,
tmpl::set<Type2>>();
assert_sets_same<tmpl::erase<tmpl::set<Type1, Type2>, Type3>,
tmpl::set<Type1, Type2>>();
This operator is overloaded for lists and for maps.

has_key<Set, T>

Returns a tmpl::integral_constant of bool indicating whether Set contains T.
assert_same<tmpl::has_key<tmpl::set<Type1, Type2>, Type2>, tmpl::true_type>();
assert_same<tmpl::has_key<tmpl::set<Type1, Type2>, Type3>, tmpl::false_type>();
This operator is overloaded for maps.

insert<Set, T>

Returns a copy of Set containing an additional element T. If T is already in the set, the set is returned unchanged.
assert_sets_same<tmpl::insert<tmpl::set<Type1, Type2>, Type3>,
tmpl::set<Type1, Type2, Type3>>();
assert_sets_same<tmpl::insert<tmpl::set<Type1, Type2>, Type1>,
tmpl::set<Type1, Type2>>();
This operator is overloaded for maps.

Mathematical functions

These perform the same operations at their language counterparts, but on tmpl::integral_constants (or anything else with a value static member type of type value_type). The results inherit from tmpl::integral_constants of types noted below.
These are all lazy metafunctions.

Arithmetic operators

These operations return classes inheriting from tmpl::integral_constants of the same type as the result of the language operator on their arguments. The integral promotion and conversion rules are applied. (Contrast the bitwise operators.)
assert_same<tmpl::plus<tmpl::size_t<10>, tmpl::size_t<3>>::type,
tmpl::size_t<13>>();
assert_same<tmpl::minus<tmpl::size_t<10>, tmpl::size_t<3>>::type,
tmpl::size_t<7>>();
assert_same<tmpl::times<tmpl::size_t<10>, tmpl::size_t<3>>::type,
tmpl::size_t<30>>();
assert_same<tmpl::divides<tmpl::size_t<10>, tmpl::size_t<3>>::type,
tmpl::size_t<3>>();
assert_same<tmpl::modulo<tmpl::size_t<10>, tmpl::size_t<3>>::type,
tmpl::size_t<1>>();
assert_same<tmpl::negate<tmpl::int64_t<10>>::type, tmpl::int64_t<-10>>();
The standard library runtime functors have the same names for std::plus, std::minus, std::divides, and std::negate, but the other two are std::multiplies and std::modulus.

Bitwise operators

These operations return classes inheriting from tmpl::integral_constants of the same type as their first argument's value. This is not generally the same type as the language operator, even when the types of the values of both arguments are the same. (The integer promotion and conversion rules are not applied.)
assert_same<tmpl::complement<tmpl::uint8_t<0b10001111>>::type,
tmpl::uint8_t<0b01110000>>();
assert_same<tmpl::bitand_<tmpl::uint8_t<0b00111011>,
tmpl::uint8_t<0b01010110>>::type,
tmpl::uint8_t<0b00010010>>();
assert_same<tmpl::bitor_<tmpl::uint8_t<0b01100011>,
tmpl::uint8_t<0b10100111>>::type,
tmpl::uint8_t<0b11100111>>();
assert_same<tmpl::bitxor_<tmpl::uint8_t<0b11000011>,
tmpl::uint8_t<0b00000110>>::type,
tmpl::uint8_t<0b11000101>>();
assert_same<tmpl::shift_left<tmpl::uint8_t<0b10001110>, tmpl::size_t<3>>::type,
tmpl::uint8_t<0b01110000>>();
assert_same<tmpl::shift_right<tmpl::uint8_t<0b10110011>, tmpl::size_t<4>>::type,
tmpl::uint8_t<0b00001011>>();
The standard library runtime functors are called std::bit_not, std::bit_and, std::bit_or, and std::bit_xor.

Comparison operators

These operations return classes inheriting from tmpl::integral_constants of bool.
assert_same<tmpl::equal_to<tmpl::size_t<1>, tmpl::size_t<2>>::type,
tmpl::false_type>();
assert_same<tmpl::not_equal_to<tmpl::size_t<1>, tmpl::size_t<2>>::type,
tmpl::true_type>();
assert_same<tmpl::greater<tmpl::size_t<1>, tmpl::size_t<2>>::type,
tmpl::false_type>();
assert_same<tmpl::greater_equal<tmpl::size_t<1>, tmpl::size_t<2>>::type,
tmpl::false_type>();
assert_same<tmpl::less<tmpl::size_t<1>, tmpl::size_t<2>>::type,
tmpl::true_type>();
assert_same<tmpl::less_equal<tmpl::size_t<1>, tmpl::size_t<2>>::type,
tmpl::true_type>();
The standard library runtime functors have the same names, such as std::equal_to.

Logical operators

These operations return classes inheriting from tmpl::integral_constants of bool. They should only be used on types wrapping bools. The and_ and or_ structs can take any number of arguments.
assert_same<tmpl::and_<>::type, tmpl::true_type>();
assert_same<tmpl::and_<std::true_type, std::false_type>::type,
tmpl::false_type>();
assert_same<tmpl::or_<>::type, tmpl::false_type>();
assert_same<tmpl::or_<std::true_type, std::false_type, std::false_type>::type,
tmpl::true_type>();
assert_same<tmpl::xor_<std::true_type, std::false_type>::type,
tmpl::true_type>();
assert_same<tmpl::not_<std::true_type>::type, tmpl::false_type>();
The standard library runtime functors are called std::logical_and, std::logical_or, and std::logical_not. The xor operation is equivalent to tmpl::not_equal_to.

identity<T>

The identity function. Unlike most math functions, this returns the same type as its argument, even if that is not a tmpl::integral_constant.
assert_same<tmpl::identity<tmpl::size_t<10>>::type, tmpl::size_t<10>>();
See also
tmpl::always

max<T1, T2>

Computes the larger of T1 and T2, returning a tmpl::integral_constant of the common type of its arguments.
assert_same<tmpl::max<tmpl::size_t<10>, tmpl::int32_t<3>>::type,
tmpl::size_t<10>>();

min<T1, T2>

Computes the smaller of T1 and T2, returning a tmpl::integral_constant of the common type of its arguments.
assert_same<tmpl::min<tmpl::size_t<10>, tmpl::int32_t<3>>::type,
tmpl::size_t<3>>();

next<T>

Computes T plus one, returning a tmpl::integral_constant of the same type as its argument.
assert_same<tmpl::next<tmpl::size_t<10>>::type, tmpl::size_t<11>>();

prev<T>

Computes T minus one, returning a tmpl::integral_constant of the same type as its argument.
assert_same<tmpl::prev<tmpl::size_t<10>>::type, tmpl::size_t<9>>();

Miscellaneous functions

Functions that don't fit into any of the other sections.

always<T>

A lazy identity function.
assert_same<tmpl::always<Type1>::type, Type1>();
See also
tmpl::identity

apply<Lambda, [Arguments...]>

Calls a metalambda Lambda with arguments Arguments....
assert_same<tmpl::apply<std::is_convertible<tmpl::_1, tmpl::_2>,
const char*, std::string>,
assert_same<tmpl::apply<std::is_convertible<tmpl::_2, tmpl::_1>,
const char*, std::string>,

count<T...>

Returns the number of template parameters provided as a tmpl::integral_constant of unsigned int.
assert_same<tmpl::count<Type1, Type2, Type1>,
tmpl::integral_constant<unsigned int, 3>>();

conditional_t<b, TrueResult, FalseResult>

Returns TrueResult if the bool b is true, otherwise FalseResult. An optimized version of std::conditional_t.
assert_same<tmpl::conditional_t<true, Type1, Type2>, Type1>();
assert_same<tmpl::conditional_t<false, Type1, Type2>, Type2>();
Note
This is not a Brigand metafunction. It is implemented in SpECTRE.

eval_if<Condition, TrueFunction, FalseFunction>

A lazy metafunction that, if Condition has a true value, evaluates and returns the result of the lazy metafunction (not metalambda) TrueFunction, otherwise, evaluates and returns the result of the lazy metafunction FalseFunction.
assert_same<tmpl::eval_if<std::true_type,
tmpl::plus<tmpl::size_t<1>, tmpl::size_t<2>>,
tmpl::plus<Type1, Type2> // Invalid expression
>::type,
tmpl::size_t<3>>();
This performs lazy evaluation of conditional branches outside of a metalambda.

eval_if_c<b, TrueFunction, FalseFunction>

The same as tmpl::eval_if, but takes its first argument as a bool instead of a type.
assert_same<tmpl::eval_if_c<true,
tmpl::plus<tmpl::size_t<1>, tmpl::size_t<2>>,
tmpl::plus<Type1, Type2> // Invalid expression
>::type,
tmpl::size_t<3>>();

has_type<Ignored, [T]>

A lazy metafunction that returns T (defaulting to void), ignoring its first argument.
assert_same<tmpl::has_type<Type1, Type2>::type, Type2>();
assert_same<tmpl::has_type<Type1>::type, void>();
This can be used to expand a parameter pack to repetitions of the same type.
template <typename... T>
bool check_sizes(const T&... containers,
const typename tmpl::has_type<T, size_t>::type... sizes) {
return (... and (containers.size() == sizes));
}
CHECK(check_sizes<std::string, std::vector<int>>("Hello", {1, 2, 3}, 5, 3));

if_<Condition, TrueResult, FalseResult>

A lazy metafunction that returns TrueResult if the value static member value of Condition is true, and otherwise FalseResult.
assert_same<tmpl::if_<std::true_type, Type1, Type2>::type, Type1>();
Warning
The second and third arguments are both evaluated, independent of which is returned. Use tmpl::defer or tmpl::eval_if if this is undesirable.

if_c<Condition, TrueResult, FalseResult>

The same as std::conditional.
assert_same<tmpl::if_c<true, Type1, Type2>::type, Type1>();

inherit<T...>

A lazy metafunction that produces a type with all of its template arguments as base classes. All the arguments must be unique.
// tmpl::type_ is used in this example because base classes must be
// complete types
static_assert(
std::is_base_of_v<tmpl::type_<Type2>,
tmpl::inherit<tmpl::type_<Type1>, tmpl::type_<Type2>,
tmpl::type_<Type3>>::type>);
Remarks
This task can be performed more simply than the algorithm used by Brigand by directly using pack expansions:
template <typename... T>
struct inherit_pack {
struct type : T... {};
};
static_assert(
std::is_base_of_v<tmpl::type_<Type2>,
inherit_pack<tmpl::type_<Type1>, tmpl::type_<Type2>,
tmpl::type_<Type3>>::type>);
Note
The tmpl::empty_base type is used internally as a sentinel. The result may or may not inherit from tmpl::empty_base, independently of whether it is supplied as an argument.

inherit_linearly<Sequence, NodePattern, [Root]>

Transforms Sequence into a linked list. The NodePattern must be a class template (not a lazy metafunction) instantiated with metalambdas. The function performs a left fold, with the Root (defaulting to tmpl::empty_base) as the initial state and the transform function evaluating the arguments to the node pattern.
assert_same<tmpl::inherit_linearly<List1<Type1, Type2>,
List2<tmpl::_1, tmpl::_2, Type3>>,
List2<List2<tmpl::empty_base, Type1, Type3>, Type2, Type3>>();
assert_same<tmpl::inherit_linearly<List1<Type1, Type2>,
List2<tmpl::_1, tmpl::_2, Type3>, Type3>,
List2<List2<Type3, Type1, Type3>, Type2, Type3>>();
HAS_LAZY_VERSION(inherit_linearly);
Remarks
This function handles its function-like argument differently from any other function in Brigand. Prefer tmpl::fold, which can perform the same task and has a more standard interface.

is_set<T...>

Tests if all of its arguments are distinct, producing a tmpl::integral_constant of bool.
assert_same<tmpl::is_set<Type1, Type2, Type3>, tmpl::true_type>();
assert_same<tmpl::is_set<Type1, Type2, Type1>, tmpl::false_type>();
assert_same<tmpl::is_set<>, tmpl::true_type>();
Note
This is unrelated to the Brigand tmpl::set type.

real_<RealType, IntType, value>

Represents a floating point number of type RealType at compile time via its internal memory representation. The value is stored as a tmpl::integral_constant of type IntType with value value (which must be the same size as RealType) and can be extracted at runtime using the conversion operator. Brigand provides the aliases single_<value> and double_<value> with RealType and IntType set to appropriate values.
using three_eighths = tmpl::single_<0x3EC00000>;
using minus_one_hundred_thousand_three = tmpl::double_<0xC0F86A3000000000>;
CHECK(static_cast<float>(three_eighths{}) == 0.375f);
CHECK(static_cast<double>(minus_one_hundred_thousand_three{}) == -100003.0);
assert_same<three_eighths::value_type, float>();
assert_same<minus_one_hundred_thousand_three::value_type, double>();
There are no compile-time mathematical functions provided for floating point types. They are opaque (or sometimes treated as integers) until runtime.
Remarks
Consider whether you really need to represent floating point values at compile time.
See also
std::ratio

repeat<Function, Count, Initial>

Calls a unary eager metafunction Function on Initial, then on the result of that, then on the result of that, and so on, up to Count calls.
assert_same<tmpl::repeat<Wrapper, tmpl::size_t<3>, Type1>,
Wrapper<Wrapper<Wrapper<Type1>>>>();
assert_same<tmpl::repeat<Wrapper, tmpl::size_t<0>, Type1>, Type1>();
Note
This function has a lazy version, but it cannot be used in a metalambda because the template template parameter prevents manipulation of the parameter list.
assert_same<tmpl::lazy::repeat<Wrapper, tmpl::size_t<3>, Type1>::type,
Wrapper<Wrapper<Wrapper<Type1>>>>();
See also
tmpl::make_sequence

sizeof_<T>

A lazy metafunction that computes sizeof its argument as an unsigned int tmpl::integral_constant.
assert_same<tmpl::sizeof_<double>::type,
tmpl::integral_constant<unsigned int, sizeof(double)>>();

substitute<Pattern, ArgumentList>

Substitutes values from ArgumentList for appearances of tmpl::args (but not tmpl::_1 or tmpl::_2) appearing in Pattern.
assert_same<tmpl::substitute<List1<List2<tmpl::_1, tmpl::_2, tmpl::_3>,
tmpl::args<0>, tmpl::args<1>, tmpl::args<2>>,
List3<Type1, Type2, Type3>>,
List1<List2<tmpl::_1, tmpl::_2, Type3>, Type1, Type2, Type3>>();

type_from<T>

Extracts the type from T.
assert_same<tmpl::type_from<tmpl::type_<Type1>>, Type1>();
Remarks
This function will work on any class with a type type alias, but, when used outside of a metafunction, it should only be used with tmpl::type_ for clarity.

wrap<Sequence, Head>

Replaces the head of Sequence with Head.
assert_same<tmpl::wrap<List1<Type1, Type2>, List2>, List2<Type1, Type2>>();
Note
This function has a lazy version, but it cannot be used in a metalambda because the template template parameter prevents manipulation of the parameter list.
assert_same<tmpl::lazy::wrap<List1<Type1, Type2>, List2>::type,
List2<Type1, Type2>>();

Runtime functionality

Brigand provides a few C++ functions that execute at runtime.
The examples in this section use the following definition:
template <typename T>
struct NonCopyable {
NonCopyable(T t = T{}) : value(std::move(t)) {}
NonCopyable(const NonCopyable&) = delete;
NonCopyable(NonCopyable&&) = default;
NonCopyable& operator=(const NonCopyable&) = delete;
NonCopyable& operator=(NonCopyable&&) = default;
T value;
template <typename... Args>
decltype(auto) operator()(Args&&... args) {
return value(std::forward<Args>(args)...);
}
};
Definition: TestHelpers.hpp:296

for_each_args(functor, arguments...)

Calls functor on each of arguments..., in order. Returns functor.
struct Functor {
Functor() = default;
Functor(const Functor&) = delete;
Functor(Functor&&) = default;
Functor& operator=(const Functor&) = delete;
Functor& operator=(Functor&&) = default;
void operator()(NonCopyable<int> x) {
record.push_back(x.value);
}
void operator()(const NonCopyable<double>& x) {
record.push_back(x.value);
}
};
const NonCopyable<double> three_point_five{3.5};
CHECK(tmpl::for_each_args(Functor{}, NonCopyable<int>{2}, three_point_five)
.record == std::vector<double>{2.0, 3.5});
Note
This uses a std::reference_wrapper internally, but I don't see a reason for that. If it were removed then this function could be constexpr starting in C++14.

for_each<Sequence>(functor)

Calls functor on tmpl::type_ objects wrapping each type in Sequence, in order. Returns functor.
struct Functor {
Functor() = default;
Functor(const Functor&) = delete;
Functor(Functor&&) = default;
Functor& operator=(const Functor&) = delete;
Functor& operator=(Functor&&) = default;
template <typename T>
void operator()(T /*t*/) {
using type = tmpl::type_from<T>;
if (std::is_same_v<type, int>) {
record.push_back("int");
} else if (std::is_same_v<type, double>) {
record.push_back("double");
}
}
};
CHECK(tmpl::for_each<List1<int, double, int>>(Functor{}).record ==
std::vector<std::string>{"int", "double", "int"});
See also
tmpl::type_from

select<Condition>(true_result, false_result)

Returns true_result if Condition's value member is true, and false_result if it is false.
const NonCopyable<std::string> hi{"Hi"};
CHECK(tmpl::select<std::true_type>(NonCopyable<int>{3}, hi).value == 3);
CHECK(tmpl::select<std::false_type>(NonCopyable<int>{3}, hi).value == "Hi");

External integration

Brigand provides metafunctions for interfacing with some types from the standard library and Boost. They usually come in pairs, with as_X taking a list and X_wrapper taking a parameter pack. This makes X_wrapper equivalent to the wrapped class.
Remarks
Avoid the *_wrapper functions in favor of using the class directly.

Boost

Brigand provides functions to produce the boost::fusion types deque, list, set, and vector, as well as boost::variant.
assert_same<tmpl::as_fusion_deque<List1<Type1, Type2, Type3>>,
boost::fusion::deque<Type1, Type2, Type3>>();
assert_same<tmpl::as_fusion_list<List1<Type1, Type2, Type3>>,
boost::fusion::list<Type1, Type2, Type3>>();
assert_same<tmpl::as_fusion_set<List1<Type1, Type2, Type3>>,
boost::fusion::set<Type1, Type2, Type3>>();
assert_same<tmpl::as_fusion_vector<List1<Type1, Type2, Type3>>,
boost::fusion::vector<Type1, Type2, Type3>>();
assert_same<tmpl::as_variant<List1<Type1, Type2, Type3>>,
boost::variant<Type1, Type2, Type3>>();
assert_same<tmpl::fusion_deque_wrapper<Type1, Type2, Type3>,
boost::fusion::deque<Type1, Type2, Type3>>();
assert_same<tmpl::fusion_list_wrapper<Type1, Type2, Type3>,
boost::fusion::list<Type1, Type2, Type3>>();
assert_same<tmpl::fusion_set_wrapper<Type1, Type2, Type3>,
boost::fusion::set<Type1, Type2, Type3>>();
assert_same<tmpl::fusion_vector_wrapper<Type1, Type2, Type3>,
boost::fusion::vector<Type1, Type2, Type3>>();
assert_same<tmpl::variant_wrapper<Type1, Type2, Type3>,
boost::variant<Type1, Type2, Type3>>();
Note
These functions are unavailable if BRIGAND_NO_BOOST_SUPPORT is defined, as is the case in SpECTRE.

STL

Brigand provides functions to produce the STL types std::pair and std::tuple. In addition to the usual functions, Brigand provides pair_wrapper_, which is a lazy form of pair_wrapper. The pair functions all assert that they have received two types.
assert_same<tmpl::as_pair<List1<Type1, Type2>>, std::pair<Type1, Type2>>();
assert_same<tmpl::as_tuple<List1<Type1, Type2, Type3>>,
assert_same<tmpl::pair_wrapper<Type1, Type2>, std::pair<Type1, Type2>>();
assert_same<tmpl::tuple_wrapper<Type1, Type2, Type3>,
assert_same<tmpl::pair_wrapper_<Type1, Type2>::type, std::pair<Type1, Type2>>();

integral_constant

Brigand provides two functions for converting from std::integral_constant (or a similar class with a value_type and a value) to tmpl::integral_constant. The lazy metafunction make_integral performs this conversion. The as_integral_list eager metafunction performs this operation on all elements of a list.
assert_same<tmpl::make_integral<std::integral_constant<char, 3>>::type,
tmpl::integral_constant<char, 3>>();
assert_same<tmpl::as_integral_list<List1<std::true_type, std::true_type,
List1<tmpl::true_type, tmpl::true_type, tmpl::false_type>>();
Warning
The standard library std::integer_sequence is not a list of types, and so cannot be used as input to as_integral_list.

list

Brigand provides two metafunctions for converting types to Brigand sequences. The more general function, as_sequence, is equivalent to tmpl::wrap. The specialized version, tmpl::as_list, produces a tmpl::list.
assert_same<tmpl::as_sequence<std::pair<Type1, Type2>, List1>,
List1<Type1, Type2>>();
assert_same<tmpl::as_list<std::pair<Type1, Type2>>, tmpl::list<Type1, Type2>>();
Remarks
Using as_list is often not necessary because most metafunctions operate on arbitrary template classes.

set

Brigand provides the standard two metafunctions for converting types to Brigand tmpl::sets.
assert_same<tmpl::as_set<std::tuple<Type1, Type2, Type3>>,
tmpl::set<Type1, Type2, Type3>>();
assert_same<tmpl::set_wrapper<Type1, Type2, Type3>,
tmpl::set<Type1, Type2, Type3>>();

Bugs/Oddities

TODO

2 tmpl::get_source
2 tmpl::get_destination
2 tmpl::edge
./adapted:
fusion.hpp - Done
integral_list.hpp - Done
list.hpp - Done
pair.hpp - Done
tuple.hpp - Done
variant.hpp - Done
./algorithms:
all.hpp - Done
any.hpp - Done
count.hpp - Done
find.hpp - Done
flatten.hpp - Done
fold.hpp - Done
for_each.hpp - Done
for_each_args.hpp - Done
index_of.hpp - Done
is_set.hpp - Done
merge.hpp - Done
none.hpp - Done
partition.hpp - Done
remove.hpp - Done
replace.hpp - Done
reverse.hpp - Done
select.hpp - Done
sort.hpp - Done
split.hpp - Done
split_at.hpp - Done
transform.hpp - Done
wrap.hpp - Done
./functions:
eval_if.hpp - Done
if.hpp - Done
./functions/arithmetic:
complement.hpp - Done
divides.hpp - Done
identity.hpp - Done
max.hpp - Done
min.hpp - Done
minus.hpp - Done
modulo.hpp - Done
negate.hpp - Done
next.hpp - Done
plus.hpp - Done
prev.hpp - Done
times.hpp - Done
./functions/bitwise:
bitand.hpp - Done
bitor.hpp - Done
bitxor.hpp - Done
shift_left.hpp - Done
shift_right.hpp - Done
./functions/comparison:
equal_to.hpp - Done
greater.hpp - Done
greater_equal.hpp - Done
less.hpp - Done
less_equal.hpp - Done
not_equal_to.hpp - Done
./functions/lambda:
apply.hpp - Done
bind.hpp - Done
substitute.hpp - Done
./functions/logical:
and.hpp - Done
not.hpp - Done
or.hpp - Done
xor.hpp - Done
./functions/misc:
always.hpp - Done
repeat.hpp - Done
sizeof.hpp - Done
./sequences:
append.hpp - Done
at.hpp - Done
back.hpp - Done
clear.hpp - Done
contains.hpp - Done
erase.hpp - Done
filled_list.hpp - Done
front.hpp - Done
has_key.hpp - Done
insert.hpp - Done
keys_as_sequence.hpp - Done
list.hpp - Done
make_sequence.hpp - Done
map.hpp - Done
pair.hpp - Done
range.hpp - Done
set.hpp - Done
size.hpp - Done
values_as_sequence.hpp - Done
./types:
args.hpp - Done
bool.hpp - Done
empty_base.hpp - Done
has_type.hpp - Done
inherit.hpp - Done
inherit_linearly.hpp - Done
integer.hpp - Done
integral_constant.hpp - Done
no_such_type.hpp - Done
operators.hpp - Broken and unused
real.hpp - Done
type.hpp - Done
voidp.hpp - Not included by main header. Special case of has_type.