Search code examples
c++fmt

A way to conditionally wrap an object in fmt::streamable() in libfmt v10+?


I'm working on a legacy project with >100 types that have an operator<< for the std ostream.

I'm using libfmt to print out vectors and sets of those types (fmt/ranges.h). Say the printout function is logPrint<typename T>(const T& arg) which prints the argument using fmt::print("{}", arg).

To expose the operator<< of those types to libfmt, I am using the fmt::detail::is_streamable template to detect if a type has a << operator.

If the template evaluates to true, I pass fmt::streamed(arg) to the fmt::print function, and if it doesn't, I just pass in arg.

Something like that: (templating removed)

#include <iostream>
#include <vector>
#include <fmt/ostream.h>
#include <fmt/ranges.h>


struct Streamable {
};


enum NonStreamableEnum {
    value
};

std::ostream& operator<<(std::ostream &os,
                         const Streamable&)
{
    return os << "Streamable";
}



int main()
{
    fmt::print("watch1: {}\n", fmt::streamed(Streamable{}));             // ok

    //fmt::print("watch2: {}\n", NonStreamableEnum::value);                // fails
    fmt::print("watch2: {}\n", fmt::streamed(NonStreamableEnum::value)); // ok

    fmt::print("watch3: {}\n", std::vector<int>({1, 2}));                // ok

    return 0;
}

Godbolt link: https://godbolt.org/z/Eox1os3x3

Now we are moving from libfmt 9.1 to libfmt 10.0 and sadly that breaks the compilation because there is no is_streamable anymore.

Question: What is the reference way in libfmt v10+ to conditionally wrap a type in fmt::streamed() depending on the presence of the << operator? Also it should printout enums and vectors like libfmt v9 did before.

Thanks


Solution

  • {fmt} doesn't provide a trait to detect operator<< so you'll need to define your own, possibly using fmt::detail::is_streamable as a starting point. For enums it's better to use format_as which can enable formatting of all enums in a namespace with a single definition and is much more efficient.