Search code examples
c++visual-c++c++17visual-studio-2019fmt

Is there a way to use fmt::output_file to write wstring to a file?


I am trying to write formatted wstring logs to file using fmt. I can do it by using fmt::format(...) and fmt::vprint but I want to use fmt::output_file to do it, however I am getting compile error.

Below code shows two ways that are working and the last one that does not work.

...
#include <fmt/format.h>
#include <fmt/xchar.h>
#include <fmt/os.h>


template <typename... Args>
static void Helper(const std::wstring& str, const Args&... args)
{
    std::filesystem::create_directories("C:\\Logs");
    std::filesystem::path file_path("C:\\Logs\\dll");

    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
    auto file_path_utf8 = converter.to_bytes(file_path.wstring());
    // Method 1 Working
    std::wofstream f_stream(file_path.string().c_str(), std::ios::app);
    f_stream << fmt::format(str, args...);
    
    // Method 2 Working
    std::FILE* file = std::fopen(file_path.string().c_str(), "a");
    fmt::vprint(file, str.c_str(), fmt::make_wformat_args(args...));
    std::fclose(file);
    
    // Method 3 NOT WORKING
    auto file = fmt::output_file(file_path.string().c_str(), fmt::file::WRONLY | fmt::file::CREATE | fmt::file::APPEND);
    file.print(str, args...);
}

With method 3 I am getting the following compilation error.

error C2664: 'void fmt::v9::ostream::print<>(fmt::v9::basic_format_string<char>)': cannot convert argument 1 from 'const std::wstring' to 'fmt::v9::basic_format_string<char>'

The example for this print member function is given on https://fmt.dev/latest/api.html#system-apis

How do I make file.print work with const std::wstring when its expecting fmt::v9::basic_format_string<char> by default?

Example mentioned on the API Ref Page


Solution

  • fmt::output_file is an experimental optimized API and as such it intentionally doesn't support wide strings because the latter would require transcoding. If you want to write wide strings you can do it with fmt::print and standard FILE or ostream:

    #include <fmt/xchar.h>
    #include <filesystem>
    
    template <typename... T>
    void helper(const std::wstring& str, T&&... args) {
      std::filesystem::path file_path("path/to/logs");
      auto file = fopen(file_path.string().c_str(), "w");
      fmt::print(file, fmt::runtime(str), std::forward<T>(args)...);
      fclose(file); // Better use RAII instead.
    }
    
    int main() {
      helper(L"{}", 42);
    }
    

    https://godbolt.org/z/aooajYWT9