This gist contains examples on how to let C++ deduce explicit template parameters.
Consider std::bit_cast
, introduced in C++20. You can use it as a replacement to std::memcpy
that can work in compile time as well. An example usage is as follows:
struct rgba final
{
std::uint8_t r;
std::uint8_t g;
std::uint8_t b;
std::uint8_t a = 255;
};
constexpr auto color = std::bit_cast<rgba>(0xffffffff);
// ^ notice how we specified the casted type as a template parameter.
With the help of the techniques used in this gist, you can instead write:
// v notice that the type is specified here
constexpr rgba color = tnt::bit_cast(0xffffffff);
// ^ we aren't using namespace std anymore
This mimics Rust's lazy type deduction (to an extent) and aims to make the code more readable. Please notice that the return type of tnt::bit_cast
stores a pointer to the passed parameter, so the following code exposes UB:
void f(std::uint32_t u) { std::cout << x; }
constexpr auto ucolor = tnt::bit_cast(rgba{255, 255, 255});
// ^ notice the `auto` here
f(ucolor);
The type of ucolor
is NOT std::uint32_t
, but it's rather a type that stores a pointer to the passed rgba
value and can be converted to std::uint32_t
(where the actual std::bit_cast
happens). Given the passed parameter is a temporary, the pointer will be dangling and thus reading it on the conversion operator is UB. For this purpose, tnt::lazy_bit_cast
is introduced, the return type of which copies the passed parameter (std::bit_cast
requires it to be trivially copyable, so it should be a cheap operation). This way the stored value will never dangle and the following code will not expose any UB.
void f(std::uint32_t u) { std::cout << x; }
constexpr auto ucolor = tnt::lazy_bit_cast(rgba{255, 255, 255});
f(ucolor); // works fine, no dangling pointers or whatever
Furthermore, an implementation of a Python-like input
function is provided, with more functions and use cases to come.
The techniques used are explained in depth (better than I could) on TartanLLama's blog post.