How do I check at compile-time if there's enough `{}` placeholders for all arguments?

315 views Asked by At

std::format has a (compile-time and runtime) format string validation, but one thing not included in this validation is whether there are enough {} placeholders for all arguments (excessive arguments are silently ignored).

I assume this could be useful in some rare cases (e.g if you generate the format string), but I don't need it, and I've had a few bugs because of this.

Is there anything I can do to check for this compile-time? Possibly by wrapping std::format in my own function.

Example:

#include <format>
#include <iostream>

int main()
{
    std::cout << std::format("{} {}", 1, 2, 3, 4, 5) << '\n'; // Prints `1 2`, no error!
}

NOTE: std::format does have compile-time format string validation. They just don't check for this specific issue (excessive arguments).

1

There are 1 answers

7
Jarod42 On

You might indeed add wrappers:

template <typename... Ts>
struct my_format_string
{
    consteval my_format_string(const char* s) :
        my_format_string(std::format_string<Ts...>(s))
    {}

    consteval my_format_string(const std::format_string<Ts...> s) : s(s)
    {
        // Use proper validation check

        // placeholder validation of the placeholders
        if (std::count(s.get().begin(), s.get().end(), '{') != sizeof...(Ts)) {
            throw 42;
        }
    }
    constexpr auto get() const { return s; }

    std::format_string<Ts...> s;
};


template <typename... Ts>
auto my_format(my_format_string<std::type_identity_t<Ts>...> format, Ts... args)
{
    return std::vformat(format.getS().get(), std::make_format_args(args...));
}

Demo