bbm::named

One use of bbm::string_literal is to create named version of any type that supports std::get (e.g., std::tuple, std::pair, std::array, etc…).

bbm::named<std::tuple<int, float, char>, "a", "b", "c"> foo(1, 2.0, 'b');
std::cout << foo << std::endl;

The above example will create a 3-element tuple, and associate the name (string_literal) “a” to the first element, “b” to the second, and “c” to the last. The purpose of named tuples is two fold:

  1. tuples are often used to return multi-value results from a function. However, a tuple requires that the programmer remembers the role of each element in the tuple, which can be error prone and might require the programmer to read the function implementation. Named tuples offer a convenient way to store a descriptive name with each tuple element.

  2. C++ does not allow for inline definition of a struct parameter or return type in a function declaration, requiring the struct to be defined separately.

Query

There several methods to query a element from a named tuple:

std::cout << std::get<0>(foo) << std::endl;   // '1'
std::cout << bbm::get<"a">(foo) << std::endl; // '1'

A compile error is throws if the requested name does not exist in the structure! Lookup and storage of names all occurs at compile time and there is no runtime overhead. One can query the type with the value_type typedef and the values of the value_type with the values() method:

std::cout << bbm::typestring< decltype(foo)::value_type > << std::endl;
std::cout << foo.values() << std::endl;

Named tuples also support structured bindings:

auto [a1, b1, c1] = foo;
std::cout << c1 << std::endl;  // 'b'

auto [a2, c2] = bbm::pick<"a", "c">(foo);
std::cout << c2 << std::endl;  // 'b'

as well as tying existing variables by name:

int a;
float b;
char c;
bbm::tie<"a", "b", "c">{a,b,c} = foo;

Note that for both pick as well as tie the order of the names does not need to correspond to the order in which they are defined. One can even repeat a name.

Query names

named types allow to check if a name is present, or to query a name:

std::cout << foo::has_name<"d"> << std::endl;  // false
std::cout << foo:names << std::endl; // yields a tuple: ("a", "b", "c")
std::cout << foo::template name<0> << std::endl; // yields "a" (use foo:size to require the length)
std::cout << foo::template find_name<"b"> << std::endl; // 1

Note find_name will return the position of the named in the value_type structure. It will return a position beyond the last element if the name does not exist (i.e., has_name == false).

bbm::make_named

A helper function is included to simplify creation of named tuples:

auto n1 = bbm::make_named<"a", "b", "c">( std::make_tuple(1, 2.0, 'b') );
auto n2 = bbm::make_named<"a", "b", "c">(1, 2.0, 'b');

In the former also works for other types that support std::get; the latter always creates a named tuple.

Recursive named types

Named types can be recursive, and bbm::get supports recursive retrieval:

auto n3 = bbm::make_named<"a">( bbm::make_named<"b", "c">('b', 'c') );

std::cout << n3 << std::endl;   // (a = (b = 'b', c = 'c'))
std::cout << bbm::get<"a">(n3) << std::endl;  // (b = 'b', c = 'c')
std::cout << bbm::get<"b">( bbm::get<"a">( n3) ) << std::endl; // 'b'
std::cout << bbm::get<"a", "b">( n3 ) << std::endl;  // 'b'

Care must be taken when constructing recursive named types:

bbm::named< bbm::named< std::tuple<int,int>, "a", "b">, "c", "d" > A{1, 2};
bbm::named< std::tuple< bbm::named< std::tuple<int,int>, "c", "d" >, "e" > B(A);

The first does not yield a recursive named type, it simply replaces the names of the inner named type with those of the outer one (i.e., (c = 1, d = 2)). The latter is a true recursive named type yielding (e = (c = 1, d = 1)).

Type traits

To check if a type is a named type, you can use bbm::is_named_v<T>. To check if two named types have the same set of names (but possibly in different order): ‘’bbm::named_equivalence_v<T, U>’’.

To remove the names from a type (also works on non-named types, i.e., it returns the non-named type unaltered):

template<typename T>
constexpr decltype(auto) bbm::anonymize_v(T &&t)
template<typename T>
using bbm::anonymize_t = std::decay_t<decltype(anonymize_v(std::declval<T>()))>

Additional Operations

Additional methods on named types are defined in util/named_util.h.

Copy by value

This method mirrors the corresponding method defined on tuples (defined in util/tuple.h, and it creates a copy of a named tuple by value (i.e., references are dereferenced):

template<typename TUP, string_literal... NAMES>
inline constexpr auto bbm::value_copy_named(const named<TUP, NAMES...> &src)

value copy a named tuple

Parameters:

src – = named tuple, possibly with references

Returns:

a copy of the named tuple without references

Corresponding type-trait:

template<typename T>
using bbm::value_copy_named_t = decltype(value_copy_named(std::declval<T>()))

type of value copying a named typle

Concat

template<typename ...T>
inline constexpr auto bbm::named_cat(T&&... t)

cat named types

named_cat( named<std::tuple<…>, “A”, “B”>{a,b}, named<std::tuple<…>, “C”>{c} )

yields

named<std::tuple<…>, “A”, B”, “C”>{a,b,c}

Corresponding type-trait:

template<typename ...T>
using bbm::named_cat_t = decltype(named_cat(std::declval<T>()...))

type of concatting multiple named tuples.

Subset

template<size_t START, size_t COUNT, typename NAMED>
inline constexpr auto bbm::subnamed(NAMED &&named)

get a subset of a named tuple

Template Parameters:
  • START – = index of first element

  • COUNT – = number of elements

Parameters:

named – = named tuple

Returns:

named tuple with elements [START, START+1, …, START+COUNT-1

Corresponding type-trait:

template<size_t START, size_t COUNT, typename NAMED>
using bbm::subnamed_t = decltype(subnamed<START, COUNT, NAMED>(std::declval<NAMED>()))

type of subnamed

Prefix and Postfix

template<string_literal PREFIX, typename T, string_literal... NAMES>
inline constexpr auto bbm::prefix_names(named<T, NAMES...> t)

prefix names in type

prefix_names<”BLA_”, named<std::tuple<…>, “A”, “B”>{a,b}

yields

named<std::tuple<…>, “BLA_A”, “BLA_B”>{a,b}

template<string_literal POSTFIX, typename T, string_literal... NAMES>
inline constexpr auto bbm::postfix_names(named<T, NAMES...> t)

postfix names in type

postfix_names<”_BLA”, named<std::tuple<…>, “A”, “B”>{a,b}

yields

named<std::tuple<…>, “A_BLA”, “B_BLA”>{a,b}

Corresponding type-traits:

template<string_literal PREFIX, typename T>
using bbm::prefix_names_t = decltype(prefix_names<PREFIX>(std::declval<T>()))

type of named tuple with pre-fixed name.

template<string_literal POSTFIX, typename T>
using bbm::postfix_names_t = decltype(post_names<POSTFIX>(std::declval<T>()))

type of named tuple with post-fixed name.

Flatten

template<typename T>
inline constexpr auto bbm::named_flatten(T &&t)

flatten a named type without merging names

named_flatten( named< std::tuple<named<std::tuple<float, char>, “A”, “B”>, int>, “C”, “D” > )

yields

named<std::tuple<float, char, int>, “A”, “B”, “D”>

template<string_literal SEP = ".", typename T>
inline constexpr auto bbm::merge_named_flatten(T &&t)

flatten a named type with merging names

merge_named_flatten( named< std::tuple<named<std::tuple<float, char>, “A”, “B”>, int>, “C”, “D” > )

yields

named<std::tuple<float, char, int>, “C.A”, “C.B”, “D”>

The default seperator symbol is “.”, but this can be changed by passing a different symbols as the first template argument.

Sorting

BBM offers the following compile-time methods for sorting and checking is a named type is sorted:

template<typename NAMED>
static constexpr bool bbm::is_named_sorted_v = detail::is_named_sorted<NAMED>()

true if named tuple is sorted by name

template<typename NAMED, size_t IDX = 0, typename PARTIAL = named<std::tuple<>>>
inline constexpr auto bbm::sort_named(NAMED &&named, PARTIAL &&partial = PARTIAL{})

sort a named tuple by name using insert-sort.

Details: this is a constexpr recursive method. It will attempt to insert the IDX-th element in PARTIAL, and then recurse to the IDX+1 element, until all elements are inserted.

Parameters:

named – = named tuple to sort

Template Parameters:
  • IDX – = start index of elements to sort; recommended default value = 0

  • PARTIAL – = partial solution to insert into; recommended default value = empty named tuple

Returns:

sorted(NAMED[IDX..END], PARTIAL)