问题
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?
回答1:
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();
}
回答2:
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
.
来源:https://stackoverflow.com/questions/16692400/c11-adding-a-stream-output-operator-for-stdchronotime-point