raberu v1.1.0
Fancy Named Parameter Library
Loading...
Searching...
No Matches
Tutorial: Customizing Keyword

Using Pre-bound keyword

Sometimes you wish you could have a terser syntax for keyword parameters. Let's say you want to pass a compile-time unrolling factor to some algorithm.

// This is working but a bit verbose
using namespace rbr::literals;
inline constexpr auto unroll = rbr::keyword("unrolling"_id);
auto x = my_algorithm( unroll = std::integral_constant<int,4>{});
constexpr any_keyword< ID > keyword(ID id) noexcept
Create a regular keyword for reuse.
Definition keywords.hpp:331
Raberu literals namespace.
Definition keywords.hpp:368

One idea is to defines a pre-bound keyword parameter, i.e constructs an inline variable initialized with the result of the assignment of a value to a keyword.

using namespace rbr::literals;
inline constexpr auto unrolling = rbr::keyword("unrolling"_id);
template<int N> inline constexpr auto unroll = (unrolling = std::integral_constant<int,N>{});

unroll<N> is now ready to be passed around. To retrieve it, you'll need to use the unrolling keyword.

#include <raberu/raberu.hpp>
#include <type_traits>
#include <iostream>
using namespace rbr::literals;
inline constexpr auto unrolling = rbr::keyword("unrolling"_id);
template<int N> inline constexpr auto unroll = (unrolling = std::integral_constant<int, N>{});
void f(rbr::concepts::option auto const& s)
{
std::cout << rbr::settings(s) << "\n";
}
int main()
{
f(unroll<8>);
}
Option concept.
Definition concepts.hpp:38
settings(Opts const &... opts) -> settings< Opts... >
rbr::settings deduction guide

Custom RABERU Keywords

The keywords provided by RABERU can also be extended to propose a better user experience. This includes using user-defined type instead of RABERU long symbol to improve diagnostic , complex checks or provide custom display when using stream insertion of settings.

Extending RABERU Keywords

Let's start again with our unrolling option. This time we want to be able to be sure nobody will use it with a non integral constant value and to display the value in a more informative way. To do so, we can inherits from rbr::as_keyword, a CRTP enabled base class:

struct unrolling : rbr::as_keyword<unrolling>
{
template<int N>
constexpr auto operator=(std::integral_constant<int,N> const&) const noexcept
{
}
std::ostream& display(std::ostream& os, auto v) const { return os << "Unroll Factor: " << v; }
};
template<int N> inline constexpr auto unroll = (unrolling{} = std::integral_constant<int,N>{});
constexpr auto operator=(Type &&v) const noexcept
Assignment of a value to a keyword.
Definition keywords.hpp:104
Base class for keyword definition.
Definition keywords.hpp:62
Callable object wrapper for functional default value.
Definition keywords.hpp:44

What if we call f( unrolling{} = 3.f ); ? Well, we go this error message:

example.cpp:25:18: error: no viable overloaded '='
f( unrolling{} = 3.f );
~~~~~~~~~~~ ^ ~~~
<source>:8:18: note: candidate template ignored: could not match 'integral_constant<int, N>' against 'float'
constexpr auto operator=(std::integral_constant<int,N> const&) const noexcept

Custom Keywords Display

Let's now improve the output of the option. Currently, the output is like:

[unrolling] : 8 (std::integral_constant<int, 8>)

A bit verbose especially for end-user. Keyword-like entity can specialize a display member function to replace this output by a custom one.

struct unrolling : rbr::as_keyword<unrolling>
{
template<int N>
constexpr auto operator=(std::integral_constant<int,N> const&) const noexcept
{
}
std::ostream& display(std::ostream& os, auto v) const { return os << "Unroll Factor: " << v; }
};

The display member takes the output stream and the actual value of the option to be displayed. One can then arrange those as they see fit, leading to a better output:

#include <raberu/raberu.hpp>
#include <type_traits>
#include <iostream>
struct unrolling : rbr::as_keyword<unrolling>
{
template<int N> constexpr auto operator=(std::integral_constant<int, N> const&) const noexcept
{
}
std::ostream& display(std::ostream& os, auto v) const { return os << "Unroll Factor: " << v; }
};
template<int N> inline constexpr auto unroll = (unrolling{} = std::integral_constant<int, N>{});
void f(rbr::concepts::option auto const& s)
{
std::cout << rbr::settings(s) << "\n";
}
int main()
{
f(unroll<8>);
}