I prefer https://github.com/rokudev/rostd/blob/main/doc/printx.adoc, but it does increase compile times (which OP was trying to avoid).
You do still need templates for the arguments (unless you're willing to resort to nasty preprocessor hackery, which would be needed if doing this in C - hmm, are the lifetime-of-temporary rules different too?), but it's pretty easy to just do:
my_asprintf_or_whatever(to_borrowed_primitive(to_owning_primitive(arg))...)
where `to_owning_primitive` is the ADL'ed function you implement for every type you want to print, and `to_borrowed_primitive` probably only needs to be implemented for each string type (though I did find it also useful for wrapped integers of unknown size/rank, such as `time_t`).