I'd prefer std::format
or fmt::format
, but this is how you can construct the format string for printf
at compile-time:
#include <algorithm>#include <cstdio>template <std::size_t N>struct ConstString{ char str[N]{}; static constexpr std::size_t size = N - 1; constexpr ConstString() {} constexpr ConstString(const char (&new_str)[N]) { std::copy_n(new_str, N, str); } constexpr operator const char *() const { return str; }};template <std::size_t A, std::size_t B>[[nodiscard]] constexpr ConstString<A + B - 1> operator+(const ConstString<A> &a, const ConstString<B> &b){ ConstString<A + B - 1> ret; std::copy_n(a.str, a.size, ret.str); std::copy_n(b.str, b.size, ret.str + a.size); return ret;}template <std::size_t A, std::size_t B>[[nodiscard]] constexpr ConstString<A + B - 1> operator+(const ConstString<A> &a, const char (&b)[B]){ return a + ConstString<B>(b);}template <std::size_t A, std::size_t B>[[nodiscard]] constexpr ConstString<A + B - 1> operator+(const char (&a)[A], const ConstString<B> &b){ return ConstString<A>(a) + b;}template <typename T>struct PrintfPlaceholder {};template <>struct PrintfPlaceholder<int> {static constexpr ConstString value = "%d";};
Then:
int main(){ int x = 42; std::printf("x = " + PrintfPlaceholder<decltype(x)>::value, x);}