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.
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.
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>
inline constexpr auto unrolling =
rbr::keyword(
"unrolling"_id);
template<int N> inline constexpr auto unroll = (unrolling = std::integral_constant<int, 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:
{
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.
{
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>
{
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>{});
{
}
int main()
{
f(unroll<8>);
}