Open h-2 opened 1 year ago
In
/* And also the algorithm */
template <typename ...Ts>
auto algo(auto data, algo_config<Ts...> const & cfg)
{
/* implementation */
}
Could you give some examples in the /* implementation */
block on how to instantiate variables of the passed type? Similar expansion in the constants /* implementation */
also.
For example, is this the most elegant way to use the passed type?
/* And also the algorithm */
template <typename ...Ts>
auto algo(auto data, algo_config<Ts...> const & cfg)
{
/* implementation */
typename decltype(cfg.int_type)::type x = 5;
std::cout << x << std::endl;
}
Also, in this line:
This would allow us to omit
align_config
also when passing “type parameters” or constants.
Should that have been algo_config
instead of align_config
?
For example, is this the most elegant way to use the passed type?
Yeah, that would be a correct way of doing it. If you want to get the implementation part a bit shorter, at the cost of adding a custom type_identity
and some more template foo, you could do the following:
/* We define a "type tag" so we can pass types as values */
template <typename T>
struct type_identity
{
using type = T;
static constexpr type_identity me{};
template <typename T2>
friend consteval bool operator==(type_identity, type_identity<T2>) noexcept
{
return std::is_same_v<T, T2>;
}
};
template <typename T>
inline constinit type_identity<T> ttag{};
/* The config now becomes a template */
template <typename Tint_type = decltype(ttag<uint64_t>)>
struct algo_config
{
bool heuristic42 = true;
Tint_type int_type = ttag<uint64_t>;
size_t threads = 4ull;
};
/* helper */
template <auto i>
using _t = typename decltype(i)::type;
/* And also the algorithm */
template <typename ...Ts>
auto algo(auto data, algo_config<Ts...> const & cfg)
{
/* implementation */
_t<cfg.int_type.me> x = 5;
if constexpr (cfg.int_type.me == ttag<uint32_t>) // 32bit path
{
// ...
}
else // default path
{
// ...
}
}
Explanation: Although type_identity
contains no state, we cannot use cfg.int_type
in constant expressions, so we can neither pass it as a template non-type argument, nor can we compare within if constexpr
. However, if we add a static constexpr
member object (me
) to the type, we can use this to avoid lots of decltype
and is_same_v
cruft in the algo.
You will have to decide whether the other changes are worth it though.
For the constants, it works much nicer right away:
template <typename ...Ts>
auto algo(auto data, algo_config<Ts...> const & cfg)
{
/* implementation */
if constexpr (cfg.use_simd.value) // SIMD implementation
{
// ...
}
else // fallback implementation
{
// ...
}
}
Should that have been algo_config instead of align_config ?
Thanks for pointing this out, will fix it in the next update of the blog!
When designing library code, one often wonders: "Are these all the parameters this function will ever need?" and "How can a user conveniently change one parameter without specifying the rest?" This post introduces some Modern C++ techniques you can use to make passing configuration options easy for your users while allowing you to add more options later on.
→ https://hannes.hauswedell.net/post/2023/03/30/algo_config/