Meta is a C++11 tiny metaprogramming library developed by Eric Niebler to facilitate the computation and manipulation of types and lists of types (aka, variadic parameter packs).
It is released under the Boost Software License and it is header only; that is, to compile with meta you just have to:
The documentation of Meta is currently scarce. The best resources are the Reference and the Examples.
As a motivation and introduction to the library you can read Eric's original blog post, but please keep in mind that the library has evolved quite a bit since then.
TODO show some simple uses. Make sure we show what Meta is good for before diving into terminology and esoteric concepts.
The tutorial begins with a brief introduction to traits, aliases, and callables. Then it moves to trait composition and currying. Finally, it covers type list algorithms and algorithms for working on integer sequences.
TODO This feels backwards. Algorithms come first. Everything else is in support of them.
Traits are class templates that have a nested type alias called (by convention) type
. For example,
is a trait taking an arbitrary number of types that always "returns" void
. There are many familiar examples of traits in the Standard Library; std::remove_reference
and std::is_void
to name two.
An alias is a synonym for a type. C++11 introduced alias templates, which are names that refer to a family of types. Alias templates simplify template syntax and smooth out interface differences. Below is an example of an alias template:
Notice how t_t<int, double>
becomes a synonym for void
. The C++14 standard library provides _t
alias templates for all the traits in the standard library.
Meta provides meta::_t<T>
, which evaluates the trait T
by aliasing the nested T::type
alias. This allows us to alias the nested type
of a trait as follows:
A Callable is a kind of alias suitable for higher-order metaprogramming. It is a class (not a template!) with a nested alias called (by convention) invoke
:
All of the algorithms that take "functions" as arguments expect Callables instead of raw aliases. Meta provides the meta::invoke<F, Args...>
alias that evaluates the Callable F
with the arguments Args
:
To turn an ordinary alias into a Callable Meta provides the meta::quote<F>
trait:
Note that in the first case we create a Callable that evaluates to the trait itself, while in the second case we create a Callable that evaluates to the nested type
of the trait.
When "quoting" a trait, it is often desirable for the resulting Callable to refer to the nested type
instead of the trait itself. For that we can use meta::quote_trait
. Consider:
Notice that meta::quote<std::add_pointer_t>
and meta::quote_trait<std::add_pointer>
mean the same thing.
Multiple Callables can be composed into a single Callable using meta::compose<F0, F1, ..., FN>
, which names a new Callable that performs F0(F1(...(FN(Args...))))
:
You can turn a Callable expecting N arguments into a Callable expecting N-M arguments by binding M arguments to the front or the back of its argument list. You can use meta::bind_front
and meta::bind_back
for that. Below we create a Callable that tests whether a type is float
by reusing the std::is_same
trait:
std::is_same
is a trait, why did we use meta::quote
instead of meta::quote_trait
? In this case, it makes no difference. In addition to being a trait, std::is_same<X, Y>
inherits from std::integral_constant<bool, true-or-false>
so we can construct an instance of std::is_same<X, Y>
and test it in a constexr
Boolean context.The traits meta::if_
, meta::and_
, meta::or_
, and meta::not_
cover the basic logical operations with types:
TODO aliases are eager,
meta::defer
,meta::lazy
namespace.
Lambda functions allow you to define Callables in place:
A list of types Ts...
can be stored in the type meta::list<Ts...>
. It provides a O(1) static member function meta::list::size()
that returns the size of the list.
As you can see, the meta::front<List>
, meta::back<List>
, and meta::at_c<List, std::size_t>
aliases provide access to the elements of the list. The meta::empty<List>
alias is std::true_type
if the list is empty. The meta::at<List, meta::size_t<N>>
alias differs from meta::at_c
in that it takes a meta::size_t<N>
(std::integral_constant<std::size_t, N>
) instead of an integer:
You can add and remove elements from a list by using the transformation algorithms:
You can concatenate, flatten, and zip multiple lists using meta::concat<Lists...>
, meta::join<ListOfLists>
, and meta::zip<ListOfLists>
:
TODO:
meta::zip_with
examples
Other typical operations on type lists include iteration, reductions, finding elements, removing duplicates:
To convert other type sequences into a meta::list
, the utility trait meta::as_list<Sequence>
is provided. For example:
To use meta with your own data types you can specialize the meta::extension::apply
trait for your own data type. For example, to use meta with C++14 std::integer_sequence
, you can:
This is a brief overview of the functionality in meta:
meta::_t
, meta::_v
, meta::invoke
, meta::defer
, meta::quote
, meta::quote_trait
, meta::id
, meta::compose
, meta::bind_front
, meta::bind_back
, meta::curry
, meta::uncurry
, meta::lambda
, meta::let
, meta::apply
.meta::list
, meta::front
, meta::back
, meta::at
, meta::at_c
. meta::empty
, meta::size
.meta::if_
, meta::and_
, meta::or_
, meta::not_
.meta::all_of
, meta::any_of
, meta::none_of
, meta::in
, meta::find
, meta::reverse_find
, meta::find_if
, meta::reverse_find_if
, meta::cout
.meta::concat
, meta::join
, meta::zip
, meta::zip_with
, meta::as_list
, meta::push_front
, meta::push_back
, meta::drop
, meta::drop_c
, meta::pop_front
, meta::fold
, meta::reverse_fold
, meta::accumulate
, meta::unique
, meta::replace
, meta::replace_if
, meta::filter
, meta::transform
, meta::reverse
, meta::cartesian_product
.meta::plus
, meta::minus
, meta::multiplies
, meta::divides
, meta::negate
, meta::modulus
, meta::equal_to
, meta::not_equal_to
, meta::greater
, meta::less
, meta::greater_equal
, meta::less_equal
, meta::bit_and
, meta::bit_or
, meta::bit_xor
, meta::bit_not
, meta::min
, meta::max
, meta::inc
, meta::dec
.meta::for_each
.See the reference section for more details.