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
{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.