Skip to content

Metafunctions

Hannes Hauswedell edited this page Apr 12, 2017 · 1 revision

We distinguish

  • value metafunctions are functions or other constructs that return a value at compile time
  • type metafunctions are constructs that return a type

Value metafunctions

There are different ways to implement value metafunctions in C++:

  1. struct templates with enum definitions
  2. struct templates with static const or static constexpr data members
  3. free constexpr functions (only meta if evaluated in constexpr context)
  4. global constexpr variable templates

In SeqAn3 we use the style of the STL which is:

  • a (possibly constrained) struct template with static constexpr value member; and
  • a shortcut of the same name, suffixed with _v as a constexpr variable template

Example:

template <typename alphabet_type>
    requires detail::internal_alphabet_concept<alphabet_type>
struct alphabet_size
{
    static constexpr underlying_integral_t<alphabet_type> value = alphabet_type::value_size;
};

template <typename alphabet_type>
constexpr underlying_integral_t<alphabet_type> alphabet_size_v = alphabet_size<alphabet_type>::value;

Note that internally, you may of course use constexpr functions or other forms of metaprogramming, but the public interfaces shall be as specified here.

Type metafunctions

There are different ways to implement type metafunctions in C++:

  1. struct templates with typedef or using declarations
  2. global templatized using declarations
  3. calling decltype() on (constexpr) functions

In SeqAn3 we use the style of the STL which is:

  • a (possibly constrained) struct template with a local type alias; and
  • a global shortcut of the same name, suffixed with _t as a templatized using declaration

Example:

template <typename alphabet_type>
    requires detail::internal_alphabet_concept<alphabet_type>
struct underlying_integral
{
    using type = typename alphabet_type::integral_type;
};

template <typename alphabet_type>
using underlying_integral_t = typename underlying_integral<alphabet_type>::type;

Specializing type metafunctions

There are different ways to specialize type metafunctions:

The first case is especially handy for template subclassing, but it has the drawback that it does not work if regular inheritance is used (which is now more often the case because we rely on concepts in other places):

template <typename type>
struct is_foo : std::false_type
{};

template <typename ...>
struct is_foo<foo_impl<...>> : std::true_type
{};
//is_foo<foo_impl<int>> == true_type

template <typename t>
struct my_type : foo_impl<t>
{
//...
};
//is_foo<my_type<int>> == false_type

The desired behaviour can be achieved with a template template and constraints:

template <typename type>
struct is_foo : std::false_type
{};

template <template <typename...> type, typename ...types>
    requires std::is_base_of_v<foo_impl<types...>, type<types...>>
struct is_foo<type<types...>> : std::true_type
{};
//is_foo<foo_impl<int>> == true_type

template <typename t>
struct my_type : foo_impl<t>
{
//...
};

//is_foo<my_type<int>> == true_type
Clone this wiki locally