I stumbled upon this code in the SerenityOS project:
template<typename... Parameters>
void dbgln(CheckedFormatString<Parameters...>&& fmtstr, const Parameters&... parameters)
They are re-implementing an equivalent of println!
from rust. An easier version of printf where you don't need to care about the argument type and is used this way:
dbgln("This is a {}", "test");
They are doing some compile time checks on the fmtstr
making sure that there are no unclosed braces and that the number of braces match the number of arguments. That's why the FormatString struct need to be templated to have access to the number of argument at compile time.
But there is something I don't understand. I wrote an MWE with the code below which, in essence, reproduce what they are doing:
#include <stddef.h>
template<typename... Args>
void compiletime_fail(Args...);
template<typename ...Parameters>
struct UnconstrainedFormatString {
template <size_t size>
consteval UnconstrainedFormatString(const char (&buffer)[size]): m_buffer(buffer), m_size(size) {
}
const char *m_buffer { nullptr };
const size_t m_size { 0 };
};
template<typename T>
struct __IdentityType {
using Type = T;
};
template<typename T>
using IdentityType = typename __IdentityType<T>::Type;
template<typename... Args>
using FormatString = UnconstrainedFormatString<IdentityType<Args>...>; // but why?
template<typename ...Parameters>
constexpr void println(FormatString<Parameters...>&& fmtstr, const Parameters& ...parameters) {
}
int main() {
println("this is a test", 1, 2, 3);
}
if I used UnconstrainedFormatString
in the println
signature I get this error from the compiler:
/cplayground/code.cpp:32:3: error: no matching function for call to 'println'
println("this is a test", 1, 2, 3);
^~~~~~~
/cplayground/code.cpp:28:16: note: candidate template ignored: could not match 'UnconstrainedFormatString<type-parameter-0-0...>' against 'char const[15]'
constexpr void println(UnconstrainedFormatString<Parameters...>&& fmtstr, const Parameters& ...parameters) {
In order for it to compile, I need to do that funky business with IdentityType
.
Why do I need this?