I would like to be able to do the following:
std::cerr << std::chrono::system_clock::now() << std::endl;
And get the following:
Wed May 1 11:11:12 2013
So I wrote the following:
template<typename Clock, typename Duration>
std::ostream &operator<<(std::ostream &stream,
const std::chrono::time_point<Clock, Duration> &time_point) {
const time_t time = Clock::to_time_t(time_point);
#if __GNUC__ > 4 || \
((__GNUC__ == 4) && __GNUC_MINOR__ > 8 && __GNUC_REVISION__ > 1)
// Maybe the put_time will be implemented later?
struct tm tm;
localtime_r(&time, &tm);
return stream << std::put_time(tm, "%c");
#else
char buffer[26];
ctime_r(&time, buffer);
buffer[24] = '\0'; // Removes the newline that is added
return stream << buffer;
#endif
}
Which works, but I keep getting issues when calling this from different namespaces. Is it correct that this should just be in the global namespace?
When you want to be sure that the right function gets called, you should put put a using
declaration in the scope of the code that will call it.
For example:
namespace pretty_time {
/* your operator<< lives here */
}
void do_stuff() {
using namespace pretty_time; // One way to go is this line
using pretty_time::operator<<; // alternative that is more specific (just use one of these two lines, but not both)
std::cout << std::chrono::system_clock::now();
}
One way to keep your mess in your own namespace
, and avoid the somewhat impolite thing of overloading an operator on two types neither of which you own, would be to make your output syntax slightly more verbose:
std::cerr << pretty_print::format(std::system_clock::now()) << std::endl;
As follows:
namespace pretty_print {
template<typename T>
struct print_wrapper { // boost::noopy optional -- if so, use it with && as an argument
T const& data;
print_wrapper( T const& t ): data(t) {}
};
template<typename T>
print_wrapper<T> format( T const& t ) {
return {t};
}
template<typename Clock, typename Duration>
std::ostream &operator<<(std::ostream &stream,
print_wrapper<std::chrono::time_point<Clock, Duration>>&& time_point)
{
// ...
}
}
and access time_point.data
to get at the raw data within your <<
overload.
The <<
operator will be found via ADL (argument dependent lookup) when you use a print_wrapper<>
wrapped type, even without pulling it into the namespace
where you use it! To use this, you can either use pretty_print::format(blah)
or you could using pretty_print::format
to pull format
into the current scope.
In effect, you have flagged the type T
for use in your own custom set of overloads. I like this technique of "thin typed wrappers" because it reminds me of std::move
.
This also lets you say "I hate how double
s are formatted", and introduce a <<
that formats them better that takes a print_wrapper<double>
.
As a side benefit, you can specialize/overload print_wrapper
and format
to take formatting arguments -- so you could pretty_print::format( std::system_clock::now(), pretty_print::eDate::YMD )
, or pretty_print::eFmt::compact
.