c++stdvectorunique-ptrc++23stdformat

Unable to std::format std::vector<std::unique_ptr<int>> in C++


I defined a formatter for std::unique_ptr<T> in my code, but when I try to print a std::vector<std::unique_ptr<int>>, I am getting the following compiler error:

std::is_default_constructible_v<std::formatter<std::vector<std::unique_ptr<int, std::default_delete<int> > >, char> >' evaluates to false

Attaching entire code (with Compiler Explorer link):

#include <format>
#include <memory>
#include <vector>
#include <iostream>

template <typename T>
    struct std::formatter<std::unique_ptr<T>> : std::formatter<std::string> {
    constexpr auto format(const std::unique_ptr<T>& e, std::format_context& ctx) const {
        if (e == nullptr)
            return std::formatter<std::string>::format("nullptr", ctx);
        return std::formatter<std::string>::format(std::format("{0}", *e), ctx);
    }
};


int main() {
    auto x = std::make_unique<int>(3);
    std::cout << std::format("{}", x);
    std::vector<std::unique_ptr<int>> vec;
    auto s = std::format("{0}", vec);
}

I want to know why the compilation failed, given that formatter for each template types are defined. Additionally, how to generically solve this issue (i.e., do I really need to define a formatter for std::vector<std::unique_ptr<T>> too?)


Solution

  • This is LWG 4240.

    The issue is that the constraint in formattable<T, char> effectively requires T to be formattable with any format_context. Unfortunately, the error diagnostic for getting this wrong is useless — you never see why std::vector<std::unique_ptr<int>> is not formattable, only that it is not. You just... need to know?

    If you change your formatter to accept any context, instead of specifically std::format_context, then it will work fine:

    - constexpr auto format(const std::unique_ptr<T>& e, std::format_context& ctx) const {
    + constexpr auto format(const std::unique_ptr<T>& e, auto& ctx) const {