Search code examples
c++fmt

Is there an fmt view for nested calls?


Sometimes, I need to effectively call fmt::format in a nested manner. e.g.

fmt::format("{}", fmt::format("{}", arg));

The real situation is more complicated than this, of course.

I'd like a view for the nested calls so that it doesn't allocate a string, do the formatting, and then allocate another one for the outer call.

Does such a thing exist?


Solution

  • You can do something like this

    template <typename Format, typename Args>
    struct nested_format_t {
        Format format;
        Args args;
    };
    
    template <typename... Args>
    auto nested_format(fmt::format_string<Args...> format, Args&&... args) {
        return nested_format_t{format, std::tuple{std::forward<Args>(args)...}};
    }
    
    template <typename Format, typename Args>
    struct fmt::formatter<nested_format_t<Format, Args>> {
        template <class ParseContext>
        constexpr ParseContext::iterator parse(ParseContext& ctx) {
            auto it = ctx.begin();
            if (it != ctx.end() && *it != '}') {
                throw "Invalid format found";
            }
            return it;
        }
    
        template <class FmtContext>
        constexpr FmtContext::iterator format(
            const nested_format_t<Format, Args>& nested, FmtContext& ctx) const {
            auto it = ctx.out();
            std::apply(
                [&](auto&&... args) {
                    fmt::vformat_to(it, nested.format,
                                    fmt::make_format_args(args...));
                },
                nested.args);
            return it;
        }
    };
    
    int main() {
        int x = 6;
        int y = 4;
        fmt::println("foo: {} {}", x, nested_format("bar {0}", y));
    }