formatting_ostream.hpp 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967
  1. /*
  2. * Copyright Andrey Semashev 2007 - 2015.
  3. * Distributed under the Boost Software License, Version 1.0.
  4. * (See accompanying file LICENSE_1_0.txt or copy at
  5. * http://www.boost.org/LICENSE_1_0.txt)
  6. */
  7. /*!
  8. * \file formatting_ostream.hpp
  9. * \author Andrey Semashev
  10. * \date 11.07.2012
  11. *
  12. * The header contains implementation of a string stream used for log record formatting.
  13. */
  14. #ifndef BOOST_LOG_UTILITY_FORMATTING_OSTREAM_HPP_INCLUDED_
  15. #define BOOST_LOG_UTILITY_FORMATTING_OSTREAM_HPP_INCLUDED_
  16. #include <ostream>
  17. #include <string>
  18. #include <memory>
  19. #include <locale>
  20. #include <boost/core/enable_if.hpp>
  21. #include <boost/core/explicit_operator_bool.hpp>
  22. #include <boost/utility/string_ref_fwd.hpp>
  23. #include <boost/utility/string_view_fwd.hpp>
  24. #include <boost/type_traits/is_enum.hpp>
  25. #include <boost/type_traits/is_scalar.hpp>
  26. #include <boost/type_traits/remove_cv.hpp>
  27. #include <boost/log/detail/config.hpp>
  28. #if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
  29. #include <string_view>
  30. #endif
  31. #include <boost/log/detail/attachable_sstream_buf.hpp>
  32. #include <boost/log/detail/code_conversion.hpp>
  33. #include <boost/log/utility/string_literal_fwd.hpp>
  34. #include <boost/log/utility/formatting_ostream_fwd.hpp>
  35. #include <boost/log/detail/header.hpp>
  36. #ifdef BOOST_HAS_PRAGMA_ONCE
  37. #pragma once
  38. #endif
  39. namespace boost {
  40. BOOST_LOG_OPEN_NAMESPACE
  41. namespace aux {
  42. template< typename T, typename R >
  43. struct enable_if_streamable_char_type {};
  44. template< typename T, typename R >
  45. struct disable_if_streamable_char_type { typedef R type; };
  46. template< typename R >
  47. struct enable_if_streamable_char_type< char, R > { typedef R type; };
  48. template< typename R >
  49. struct disable_if_streamable_char_type< char, R > {};
  50. template< typename R >
  51. struct enable_if_streamable_char_type< wchar_t, R > { typedef R type; };
  52. template< typename R >
  53. struct disable_if_streamable_char_type< wchar_t, R > {};
  54. #if !defined(BOOST_LOG_NO_CXX11_CODECVT_FACETS)
  55. #if !defined(BOOST_NO_CXX11_CHAR16_T)
  56. template< typename R >
  57. struct enable_if_streamable_char_type< char16_t, R > { typedef R type; };
  58. template< typename R >
  59. struct disable_if_streamable_char_type< char16_t, R > {};
  60. #endif
  61. #if !defined(BOOST_NO_CXX11_CHAR32_T)
  62. template< typename R >
  63. struct enable_if_streamable_char_type< char32_t, R > { typedef R type; };
  64. template< typename R >
  65. struct disable_if_streamable_char_type< char32_t, R > {};
  66. #endif
  67. #endif
  68. template< typename StreamT, typename T, bool ByValueV, typename R >
  69. struct enable_formatting_ostream_generic_operator {};
  70. template< typename CharT, typename TraitsT, typename AllocatorT, typename T, typename R >
  71. struct enable_formatting_ostream_generic_operator< basic_formatting_ostream< CharT, TraitsT, AllocatorT >, T, false, R > :
  72. public boost::disable_if_c< boost::is_scalar< typename boost::remove_cv< T >::type >::value, R >
  73. {
  74. };
  75. template< typename CharT, typename TraitsT, typename AllocatorT, typename T, typename R >
  76. struct enable_formatting_ostream_generic_operator< basic_formatting_ostream< CharT, TraitsT, AllocatorT >, T, true, R > :
  77. public boost::enable_if_c< boost::is_enum< typename boost::remove_cv< T >::type >::value, R >
  78. {
  79. };
  80. template< typename CharT, typename TraitsT, typename AllocatorT, typename T, typename R >
  81. struct enable_formatting_ostream_generic_operator< basic_formatting_ostream< CharT, TraitsT, AllocatorT >, T*, true, R > :
  82. public disable_if_streamable_char_type< typename boost::remove_cv< T >::type, R >
  83. {
  84. };
  85. } // namespace aux
  86. /*!
  87. * \brief Stream wrapper for log records formatting.
  88. *
  89. * This stream wrapper is used by the library for log record formatting. It implements the standard string stream interface
  90. * with a few differences:
  91. *
  92. * \li It does not derive from standard types <tt>std::basic_ostream</tt>, <tt>std::basic_ios</tt> and <tt>std::ios_base</tt>,
  93. * although it tries to implement their interfaces closely. There are a few small differences, mostly regarding <tt>rdbuf</tt>
  94. * and <tt>str</tt> signatures, as well as the supported insertion operator overloads. The actual wrapped stream can be accessed
  95. * through the <tt>stream</tt> methods.
  96. * \li By default, \c bool values are formatted using alphabetical representation rather than numeric.
  97. * \li The stream supports writing strings of character types different from the stream character type. The stream will perform
  98. * character code conversion as needed using the imbued locale.
  99. * \li The stream operates on an external string object rather than on the embedded one. The string can be attached or detached
  100. * from the stream dynamically.
  101. *
  102. * Although <tt>basic_formatting_ostream</tt> does not derive from <tt>std::basic_ostream</tt>, users are not required to add
  103. * special overloads of \c operator<< for it since the stream will by default reuse the operators for <tt>std::basic_ostream</tt>.
  104. * However, one can define special overloads of \c operator<< for <tt>basic_formatting_ostream</tt> if a certain type needs
  105. * special formatting when output to log.
  106. */
  107. template< typename CharT, typename TraitsT, typename AllocatorT >
  108. class basic_formatting_ostream
  109. {
  110. public:
  111. //! Character type
  112. typedef CharT char_type;
  113. //! Character traits
  114. typedef TraitsT traits_type;
  115. //! Memory allocator
  116. typedef AllocatorT allocator_type;
  117. //! Stream buffer type
  118. typedef boost::log::aux::basic_ostringstreambuf< char_type, traits_type, allocator_type > streambuf_type;
  119. //! Target string type
  120. typedef typename streambuf_type::string_type string_type;
  121. //! Stream type
  122. typedef std::basic_ostream< char_type, traits_type > ostream_type;
  123. //! Stream position type
  124. typedef typename ostream_type::pos_type pos_type;
  125. //! Stream offset type
  126. typedef typename ostream_type::off_type off_type;
  127. //! Integer type for characters
  128. typedef typename ostream_type::int_type int_type;
  129. typedef typename ostream_type::failure failure;
  130. typedef typename ostream_type::fmtflags fmtflags;
  131. typedef typename ostream_type::iostate iostate;
  132. typedef typename ostream_type::openmode openmode;
  133. typedef typename ostream_type::seekdir seekdir;
  134. typedef typename ostream_type::Init Init;
  135. typedef typename ostream_type::event event;
  136. typedef typename ostream_type::event_callback event_callback;
  137. class sentry :
  138. public ostream_type::sentry
  139. {
  140. typedef typename ostream_type::sentry base_type;
  141. public:
  142. explicit sentry(basic_formatting_ostream& strm) : base_type(strm.stream())
  143. {
  144. }
  145. // A workaround for Solaris Studio 12.4 compiler, see: https://svn.boost.org/trac/boost/ticket/11545
  146. BOOST_EXPLICIT_OPERATOR_BOOL()
  147. bool operator! () const { return !static_cast< base_type const& >(*this); }
  148. BOOST_DELETED_FUNCTION(sentry(sentry const&))
  149. BOOST_DELETED_FUNCTION(sentry& operator= (sentry const&))
  150. };
  151. protected:
  152. // Function types
  153. typedef std::ios_base& (*ios_base_manip)(std::ios_base&);
  154. typedef std::basic_ios< char_type, traits_type >& (*basic_ios_manip)(std::basic_ios< char_type, traits_type >&);
  155. typedef ostream_type& (*stream_manip)(ostream_type&);
  156. public:
  157. static BOOST_CONSTEXPR_OR_CONST fmtflags boolalpha = ostream_type::boolalpha;
  158. static BOOST_CONSTEXPR_OR_CONST fmtflags dec = ostream_type::dec;
  159. static BOOST_CONSTEXPR_OR_CONST fmtflags fixed = ostream_type::fixed;
  160. static BOOST_CONSTEXPR_OR_CONST fmtflags hex = ostream_type::hex;
  161. static BOOST_CONSTEXPR_OR_CONST fmtflags internal = ostream_type::internal;
  162. static BOOST_CONSTEXPR_OR_CONST fmtflags left = ostream_type::left;
  163. static BOOST_CONSTEXPR_OR_CONST fmtflags oct = ostream_type::oct;
  164. static BOOST_CONSTEXPR_OR_CONST fmtflags right = ostream_type::right;
  165. static BOOST_CONSTEXPR_OR_CONST fmtflags scientific = ostream_type::scientific;
  166. static BOOST_CONSTEXPR_OR_CONST fmtflags showbase = ostream_type::showbase;
  167. static BOOST_CONSTEXPR_OR_CONST fmtflags showpoint = ostream_type::showpoint;
  168. static BOOST_CONSTEXPR_OR_CONST fmtflags skipws = ostream_type::skipws;
  169. static BOOST_CONSTEXPR_OR_CONST fmtflags unitbuf = ostream_type::unitbuf;
  170. static BOOST_CONSTEXPR_OR_CONST fmtflags uppercase = ostream_type::uppercase;
  171. static BOOST_CONSTEXPR_OR_CONST fmtflags adjustfield = ostream_type::adjustfield;
  172. static BOOST_CONSTEXPR_OR_CONST fmtflags basefield = ostream_type::basefield;
  173. static BOOST_CONSTEXPR_OR_CONST fmtflags floatfield = ostream_type::floatfield;
  174. static BOOST_CONSTEXPR_OR_CONST iostate badbit = ostream_type::badbit;
  175. static BOOST_CONSTEXPR_OR_CONST iostate eofbit = ostream_type::eofbit;
  176. static BOOST_CONSTEXPR_OR_CONST iostate failbit = ostream_type::failbit;
  177. static BOOST_CONSTEXPR_OR_CONST iostate goodbit = ostream_type::goodbit;
  178. static BOOST_CONSTEXPR_OR_CONST openmode app = ostream_type::app;
  179. static BOOST_CONSTEXPR_OR_CONST openmode ate = ostream_type::ate;
  180. static BOOST_CONSTEXPR_OR_CONST openmode binary = ostream_type::binary;
  181. static BOOST_CONSTEXPR_OR_CONST openmode in = ostream_type::in;
  182. static BOOST_CONSTEXPR_OR_CONST openmode out = ostream_type::out;
  183. static BOOST_CONSTEXPR_OR_CONST openmode trunc = ostream_type::trunc;
  184. static BOOST_CONSTEXPR_OR_CONST seekdir beg = ostream_type::beg;
  185. static BOOST_CONSTEXPR_OR_CONST seekdir cur = ostream_type::cur;
  186. static BOOST_CONSTEXPR_OR_CONST seekdir end = ostream_type::end;
  187. static BOOST_CONSTEXPR_OR_CONST event erase_event = ostream_type::erase_event;
  188. static BOOST_CONSTEXPR_OR_CONST event imbue_event = ostream_type::imbue_event;
  189. static BOOST_CONSTEXPR_OR_CONST event copyfmt_event = ostream_type::copyfmt_event;
  190. private:
  191. mutable streambuf_type m_streambuf;
  192. ostream_type m_stream;
  193. public:
  194. /*!
  195. * Default constructor. Creates an empty record that is equivalent to the invalid record handle.
  196. * The stream capability is not available after construction.
  197. *
  198. * \post <tt>!*this == true</tt>
  199. */
  200. basic_formatting_ostream() : m_stream(&m_streambuf)
  201. {
  202. init_stream();
  203. }
  204. /*!
  205. * Initializing constructor. Attaches the string to the constructed stream.
  206. * The string will be used to store the formatted characters.
  207. *
  208. * \post <tt>!*this == false</tt>
  209. * \param str The string buffer to attach.
  210. */
  211. explicit basic_formatting_ostream(string_type& str) :
  212. m_streambuf(str),
  213. m_stream(&m_streambuf)
  214. {
  215. init_stream();
  216. }
  217. /*!
  218. * Destructor. Destroys the record, releases any sinks and attribute values that were involved in processing this record.
  219. */
  220. ~basic_formatting_ostream()
  221. {
  222. if (m_streambuf.storage())
  223. flush();
  224. }
  225. /*!
  226. * Attaches the stream to the string. The string will be used to store the formatted characters.
  227. *
  228. * \param str The string buffer to attach.
  229. */
  230. void attach(string_type& str)
  231. {
  232. m_streambuf.attach(str);
  233. m_stream.clear(ostream_type::goodbit);
  234. }
  235. /*!
  236. * Detaches the stream from the string. Any buffered data is flushed to the string.
  237. */
  238. void detach()
  239. {
  240. m_streambuf.detach();
  241. m_stream.clear(ostream_type::badbit);
  242. }
  243. /*!
  244. * \returns Reference to the attached string. The string must be attached before calling this method.
  245. */
  246. string_type const& str() const
  247. {
  248. string_type* const storage = m_streambuf.storage();
  249. BOOST_ASSERT(storage != NULL);
  250. m_streambuf.pubsync();
  251. return *storage;
  252. }
  253. /*!
  254. * \returns Reference to the wrapped stream
  255. */
  256. ostream_type& stream() { return m_stream; }
  257. /*!
  258. * \returns Reference to the wrapped stream
  259. */
  260. ostream_type const& stream() const { return m_stream; }
  261. // std::ios_base method forwarders
  262. fmtflags flags() const { return m_stream.flags(); }
  263. fmtflags flags(fmtflags f) { return m_stream.flags(f); }
  264. fmtflags setf(fmtflags f) { return m_stream.setf(f); }
  265. fmtflags setf(fmtflags f, fmtflags mask) { return m_stream.setf(f, mask); }
  266. void unsetf(fmtflags f) { m_stream.unsetf(f); }
  267. std::streamsize precision() const { return m_stream.precision(); }
  268. std::streamsize precision(std::streamsize p) { return m_stream.precision(p); }
  269. std::streamsize width() const { return m_stream.width(); }
  270. std::streamsize width(std::streamsize w) { return m_stream.width(w); }
  271. std::locale getloc() const { return m_stream.getloc(); }
  272. std::locale imbue(std::locale const& loc) { return m_stream.imbue(loc); }
  273. static int xalloc() { return ostream_type::xalloc(); }
  274. long& iword(int index) { return m_stream.iword(index); }
  275. void*& pword(int index) { return m_stream.pword(index); }
  276. void register_callback(event_callback fn, int index) { m_stream.register_callback(fn, index); }
  277. static bool sync_with_stdio(bool sync = true) { return ostream_type::sync_with_stdio(sync); }
  278. // std::basic_ios method forwarders
  279. BOOST_EXPLICIT_OPERATOR_BOOL()
  280. bool operator! () const { return !m_stream; }
  281. iostate rdstate() const { return m_stream.rdstate(); }
  282. void clear(iostate state = goodbit) { m_stream.clear(state); }
  283. void setstate(iostate state) { m_stream.setstate(state); }
  284. bool good() const { return m_stream.good(); }
  285. bool eof() const { return m_stream.eof(); }
  286. bool fail() const { return m_stream.fail(); }
  287. bool bad() const { return m_stream.bad(); }
  288. iostate exceptions() const { return m_stream.exceptions(); }
  289. void exceptions(iostate s) { m_stream.exceptions(s); }
  290. ostream_type* tie() const { return m_stream.tie(); }
  291. ostream_type* tie(ostream_type* strm) { return m_stream.tie(strm); }
  292. streambuf_type* rdbuf() const { return &m_streambuf; }
  293. basic_formatting_ostream& copyfmt(std::basic_ios< char_type, traits_type >& rhs)
  294. {
  295. m_stream.copyfmt(rhs);
  296. return *this;
  297. }
  298. basic_formatting_ostream& copyfmt(basic_formatting_ostream& rhs)
  299. {
  300. m_stream.copyfmt(rhs.stream());
  301. return *this;
  302. }
  303. char_type fill() const { return m_stream.fill(); }
  304. char_type fill(char_type ch) { return m_stream.fill(ch); }
  305. char narrow(char_type ch, char def) const { return m_stream.narrow(ch, def); }
  306. char_type widen(char ch) const { return m_stream.widen(ch); }
  307. // std::basic_ostream method forwarders
  308. basic_formatting_ostream& flush()
  309. {
  310. m_stream.flush();
  311. return *this;
  312. }
  313. pos_type tellp() { return m_stream.tellp(); }
  314. basic_formatting_ostream& seekp(pos_type pos)
  315. {
  316. m_stream.seekp(pos);
  317. return *this;
  318. }
  319. basic_formatting_ostream& seekp(off_type off, std::ios_base::seekdir dir)
  320. {
  321. m_stream.seekp(off, dir);
  322. return *this;
  323. }
  324. basic_formatting_ostream& put(char_type c)
  325. {
  326. m_stream.put(c);
  327. return *this;
  328. }
  329. template< typename OtherCharT >
  330. typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
  331. put(OtherCharT c)
  332. {
  333. write(&c, 1);
  334. return *this;
  335. }
  336. basic_formatting_ostream& write(const char_type* p, std::streamsize size)
  337. {
  338. m_stream.write(p, size);
  339. return *this;
  340. }
  341. template< typename OtherCharT >
  342. typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
  343. write(const OtherCharT* p, std::streamsize size)
  344. {
  345. sentry guard(*this);
  346. if (!!guard)
  347. {
  348. m_stream.flush();
  349. if (!m_streambuf.storage_overflow())
  350. {
  351. string_type* storage = m_streambuf.storage();
  352. if (!aux::code_convert(p, static_cast< std::size_t >(size), *storage, m_streambuf.max_size(), m_stream.getloc()))
  353. m_streambuf.storage_overflow(true);
  354. }
  355. }
  356. return *this;
  357. }
  358. basic_formatting_ostream& operator<< (ios_base_manip manip)
  359. {
  360. m_stream << manip;
  361. return *this;
  362. }
  363. basic_formatting_ostream& operator<< (basic_ios_manip manip)
  364. {
  365. m_stream << manip;
  366. return *this;
  367. }
  368. basic_formatting_ostream& operator<< (stream_manip manip)
  369. {
  370. m_stream << manip;
  371. return *this;
  372. }
  373. basic_formatting_ostream& operator<< (char c)
  374. {
  375. return this->formatted_write(&c, 1);
  376. }
  377. basic_formatting_ostream& operator<< (const char* p)
  378. {
  379. return this->formatted_write(p, static_cast< std::streamsize >(std::char_traits< char >::length(p)));
  380. }
  381. // When no native character type is supported, the following overloads are disabled as they have ambiguous meaning.
  382. // Use basic_string_view or basic_string to explicitly indicate that the data is a string.
  383. #if !defined(BOOST_NO_INTRINSIC_WCHAR_T)
  384. basic_formatting_ostream& operator<< (wchar_t c)
  385. {
  386. return this->formatted_write(&c, 1);
  387. }
  388. basic_formatting_ostream& operator<< (const wchar_t* p)
  389. {
  390. return this->formatted_write(p, static_cast< std::streamsize >(std::char_traits< wchar_t >::length(p)));
  391. }
  392. #endif
  393. #if !defined(BOOST_LOG_NO_CXX11_CODECVT_FACETS)
  394. #if !defined(BOOST_NO_CXX11_CHAR16_T)
  395. basic_formatting_ostream& operator<< (char16_t c)
  396. {
  397. return this->formatted_write(&c, 1);
  398. }
  399. basic_formatting_ostream& operator<< (const char16_t* p)
  400. {
  401. return this->formatted_write(p, static_cast< std::streamsize >(std::char_traits< char16_t >::length(p)));
  402. }
  403. #endif
  404. #if !defined(BOOST_NO_CXX11_CHAR32_T)
  405. basic_formatting_ostream& operator<< (char32_t c)
  406. {
  407. return this->formatted_write(&c, 1);
  408. }
  409. basic_formatting_ostream& operator<< (const char32_t* p)
  410. {
  411. return this->formatted_write(p, static_cast< std::streamsize >(std::char_traits< char32_t >::length(p)));
  412. }
  413. #endif
  414. #endif
  415. basic_formatting_ostream& operator<< (bool value)
  416. {
  417. m_stream << value;
  418. return *this;
  419. }
  420. basic_formatting_ostream& operator<< (signed char value)
  421. {
  422. m_stream << value;
  423. return *this;
  424. }
  425. basic_formatting_ostream& operator<< (unsigned char value)
  426. {
  427. m_stream << value;
  428. return *this;
  429. }
  430. basic_formatting_ostream& operator<< (short value)
  431. {
  432. m_stream << value;
  433. return *this;
  434. }
  435. basic_formatting_ostream& operator<< (unsigned short value)
  436. {
  437. m_stream << value;
  438. return *this;
  439. }
  440. basic_formatting_ostream& operator<< (int value)
  441. {
  442. m_stream << value;
  443. return *this;
  444. }
  445. basic_formatting_ostream& operator<< (unsigned int value)
  446. {
  447. m_stream << value;
  448. return *this;
  449. }
  450. basic_formatting_ostream& operator<< (long value)
  451. {
  452. m_stream << value;
  453. return *this;
  454. }
  455. basic_formatting_ostream& operator<< (unsigned long value)
  456. {
  457. m_stream << value;
  458. return *this;
  459. }
  460. #if !defined(BOOST_NO_LONG_LONG)
  461. basic_formatting_ostream& operator<< (long long value)
  462. {
  463. m_stream << value;
  464. return *this;
  465. }
  466. basic_formatting_ostream& operator<< (unsigned long long value)
  467. {
  468. m_stream << value;
  469. return *this;
  470. }
  471. #endif
  472. basic_formatting_ostream& operator<< (float value)
  473. {
  474. m_stream << value;
  475. return *this;
  476. }
  477. basic_formatting_ostream& operator<< (double value)
  478. {
  479. m_stream << value;
  480. return *this;
  481. }
  482. basic_formatting_ostream& operator<< (long double value)
  483. {
  484. m_stream << value;
  485. return *this;
  486. }
  487. basic_formatting_ostream& operator<< (std::basic_streambuf< char_type, traits_type >* buf)
  488. {
  489. m_stream << buf;
  490. return *this;
  491. }
  492. template< typename OtherCharT, typename OtherTraitsT, typename OtherAllocatorT >
  493. friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
  494. operator<< (basic_formatting_ostream& strm, std::basic_string< OtherCharT, OtherTraitsT, OtherAllocatorT > const& str)
  495. {
  496. return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
  497. }
  498. #if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
  499. template< typename OtherCharT, typename OtherTraitsT >
  500. friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
  501. operator<< (basic_formatting_ostream& strm, std::basic_string_view< OtherCharT, OtherTraitsT > const& str)
  502. {
  503. return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
  504. }
  505. #endif
  506. template< typename OtherCharT, typename OtherTraitsT >
  507. friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
  508. operator<< (basic_formatting_ostream& strm, basic_string_literal< OtherCharT, OtherTraitsT > const& str)
  509. {
  510. return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
  511. }
  512. template< typename OtherCharT, typename OtherTraitsT >
  513. friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
  514. operator<< (basic_formatting_ostream& strm, basic_string_view< OtherCharT, OtherTraitsT > const& str)
  515. {
  516. return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
  517. }
  518. // Deprecated overload
  519. template< typename OtherCharT, typename OtherTraitsT >
  520. friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
  521. operator<< (basic_formatting_ostream& strm, basic_string_ref< OtherCharT, OtherTraitsT > const& str)
  522. {
  523. return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
  524. }
  525. template< typename OtherCharT, typename OtherTraitsT, typename OtherAllocatorT >
  526. friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
  527. operator<< (basic_formatting_ostream& strm, std::basic_string< OtherCharT, OtherTraitsT, OtherAllocatorT >& str)
  528. {
  529. return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
  530. }
  531. #if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
  532. template< typename OtherCharT, typename OtherTraitsT >
  533. friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
  534. operator<< (basic_formatting_ostream& strm, std::basic_string_view< OtherCharT, OtherTraitsT >& str)
  535. {
  536. return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
  537. }
  538. #endif
  539. template< typename OtherCharT, typename OtherTraitsT >
  540. friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
  541. operator<< (basic_formatting_ostream& strm, basic_string_literal< OtherCharT, OtherTraitsT >& str)
  542. {
  543. return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
  544. }
  545. template< typename OtherCharT, typename OtherTraitsT >
  546. friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
  547. operator<< (basic_formatting_ostream& strm, basic_string_view< OtherCharT, OtherTraitsT >& str)
  548. {
  549. return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
  550. }
  551. // Deprecated overload
  552. template< typename OtherCharT, typename OtherTraitsT >
  553. friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
  554. operator<< (basic_formatting_ostream& strm, basic_string_ref< OtherCharT, OtherTraitsT >& str)
  555. {
  556. return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
  557. }
  558. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  559. template< typename OtherCharT, typename OtherTraitsT, typename OtherAllocatorT >
  560. friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
  561. operator<< (basic_formatting_ostream&& strm, std::basic_string< OtherCharT, OtherTraitsT, OtherAllocatorT > const& str)
  562. {
  563. return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
  564. }
  565. #if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
  566. template< typename OtherCharT, typename OtherTraitsT >
  567. friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
  568. operator<< (basic_formatting_ostream&& strm, std::basic_string_view< OtherCharT, OtherTraitsT > const& str)
  569. {
  570. return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
  571. }
  572. #endif
  573. template< typename OtherCharT, typename OtherTraitsT >
  574. friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
  575. operator<< (basic_formatting_ostream&& strm, basic_string_literal< OtherCharT, OtherTraitsT > const& str)
  576. {
  577. return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
  578. }
  579. template< typename OtherCharT, typename OtherTraitsT >
  580. friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
  581. operator<< (basic_formatting_ostream&& strm, basic_string_view< OtherCharT, OtherTraitsT > const& str)
  582. {
  583. return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
  584. }
  585. // Deprecated overload
  586. template< typename OtherCharT, typename OtherTraitsT >
  587. friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
  588. operator<< (basic_formatting_ostream&& strm, basic_string_ref< OtherCharT, OtherTraitsT > const& str)
  589. {
  590. return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
  591. }
  592. template< typename OtherCharT, typename OtherTraitsT, typename OtherAllocatorT >
  593. friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
  594. operator<< (basic_formatting_ostream&& strm, std::basic_string< OtherCharT, OtherTraitsT, OtherAllocatorT >& str)
  595. {
  596. return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
  597. }
  598. #if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
  599. template< typename OtherCharT, typename OtherTraitsT >
  600. friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
  601. operator<< (basic_formatting_ostream&& strm, std::basic_string_view< OtherCharT, OtherTraitsT >& str)
  602. {
  603. return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
  604. }
  605. #endif
  606. template< typename OtherCharT, typename OtherTraitsT >
  607. friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
  608. operator<< (basic_formatting_ostream&& strm, basic_string_literal< OtherCharT, OtherTraitsT >& str)
  609. {
  610. return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
  611. }
  612. template< typename OtherCharT, typename OtherTraitsT >
  613. friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
  614. operator<< (basic_formatting_ostream&& strm, basic_string_view< OtherCharT, OtherTraitsT >& str)
  615. {
  616. return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
  617. }
  618. // Deprecated overload
  619. template< typename OtherCharT, typename OtherTraitsT >
  620. friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
  621. operator<< (basic_formatting_ostream&& strm, basic_string_ref< OtherCharT, OtherTraitsT >& str)
  622. {
  623. return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
  624. }
  625. #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  626. protected:
  627. void init_stream()
  628. {
  629. m_stream.exceptions(ostream_type::goodbit);
  630. m_stream.clear(m_streambuf.storage() ? ostream_type::goodbit : ostream_type::badbit);
  631. m_stream.flags
  632. (
  633. ostream_type::dec |
  634. ostream_type::skipws |
  635. ostream_type::boolalpha // this differs from the default stream flags but makes logs look better
  636. );
  637. m_stream.width(0);
  638. m_stream.precision(6);
  639. m_stream.fill(static_cast< char_type >(' '));
  640. }
  641. private:
  642. basic_formatting_ostream& formatted_write(const char_type* p, std::streamsize size)
  643. {
  644. sentry guard(*this);
  645. if (!!guard)
  646. {
  647. m_stream.flush();
  648. if (m_stream.width() <= size)
  649. m_streambuf.append(p, static_cast< std::size_t >(size));
  650. else
  651. this->aligned_write(p, size);
  652. m_stream.width(0);
  653. }
  654. return *this;
  655. }
  656. template< typename OtherCharT >
  657. basic_formatting_ostream& formatted_write(const OtherCharT* p, std::streamsize size)
  658. {
  659. sentry guard(*this);
  660. if (!!guard)
  661. {
  662. m_stream.flush();
  663. if (m_stream.width() <= size)
  664. {
  665. if (!m_streambuf.storage_overflow())
  666. {
  667. if (!aux::code_convert(p, static_cast< std::size_t >(size), *m_streambuf.storage(), m_streambuf.max_size(), m_stream.getloc()))
  668. m_streambuf.storage_overflow(true);
  669. }
  670. }
  671. else
  672. this->aligned_write(p, size);
  673. m_stream.width(0);
  674. }
  675. return *this;
  676. }
  677. void aligned_write(const char_type* p, std::streamsize size);
  678. template< typename OtherCharT >
  679. void aligned_write(const OtherCharT* p, std::streamsize size);
  680. //! Copy constructor (closed)
  681. BOOST_DELETED_FUNCTION(basic_formatting_ostream(basic_formatting_ostream const& that))
  682. //! Assignment (closed)
  683. BOOST_DELETED_FUNCTION(basic_formatting_ostream& operator= (basic_formatting_ostream const& that))
  684. };
  685. template< typename CharT, typename TraitsT, typename AllocatorT >
  686. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::boolalpha;
  687. template< typename CharT, typename TraitsT, typename AllocatorT >
  688. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::dec;
  689. template< typename CharT, typename TraitsT, typename AllocatorT >
  690. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fixed;
  691. template< typename CharT, typename TraitsT, typename AllocatorT >
  692. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::hex;
  693. template< typename CharT, typename TraitsT, typename AllocatorT >
  694. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::internal;
  695. template< typename CharT, typename TraitsT, typename AllocatorT >
  696. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::left;
  697. template< typename CharT, typename TraitsT, typename AllocatorT >
  698. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::oct;
  699. template< typename CharT, typename TraitsT, typename AllocatorT >
  700. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::right;
  701. template< typename CharT, typename TraitsT, typename AllocatorT >
  702. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::scientific;
  703. template< typename CharT, typename TraitsT, typename AllocatorT >
  704. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::showbase;
  705. template< typename CharT, typename TraitsT, typename AllocatorT >
  706. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::showpoint;
  707. template< typename CharT, typename TraitsT, typename AllocatorT >
  708. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::skipws;
  709. template< typename CharT, typename TraitsT, typename AllocatorT >
  710. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::unitbuf;
  711. template< typename CharT, typename TraitsT, typename AllocatorT >
  712. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::uppercase;
  713. template< typename CharT, typename TraitsT, typename AllocatorT >
  714. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::adjustfield;
  715. template< typename CharT, typename TraitsT, typename AllocatorT >
  716. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::basefield;
  717. template< typename CharT, typename TraitsT, typename AllocatorT >
  718. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::floatfield;
  719. template< typename CharT, typename TraitsT, typename AllocatorT >
  720. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::iostate basic_formatting_ostream< CharT, TraitsT, AllocatorT >::badbit;
  721. template< typename CharT, typename TraitsT, typename AllocatorT >
  722. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::iostate basic_formatting_ostream< CharT, TraitsT, AllocatorT >::eofbit;
  723. template< typename CharT, typename TraitsT, typename AllocatorT >
  724. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::iostate basic_formatting_ostream< CharT, TraitsT, AllocatorT >::failbit;
  725. template< typename CharT, typename TraitsT, typename AllocatorT >
  726. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::iostate basic_formatting_ostream< CharT, TraitsT, AllocatorT >::goodbit;
  727. template< typename CharT, typename TraitsT, typename AllocatorT >
  728. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::openmode basic_formatting_ostream< CharT, TraitsT, AllocatorT >::app;
  729. template< typename CharT, typename TraitsT, typename AllocatorT >
  730. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::openmode basic_formatting_ostream< CharT, TraitsT, AllocatorT >::ate;
  731. template< typename CharT, typename TraitsT, typename AllocatorT >
  732. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::openmode basic_formatting_ostream< CharT, TraitsT, AllocatorT >::binary;
  733. template< typename CharT, typename TraitsT, typename AllocatorT >
  734. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::openmode basic_formatting_ostream< CharT, TraitsT, AllocatorT >::in;
  735. template< typename CharT, typename TraitsT, typename AllocatorT >
  736. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::openmode basic_formatting_ostream< CharT, TraitsT, AllocatorT >::out;
  737. template< typename CharT, typename TraitsT, typename AllocatorT >
  738. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::openmode basic_formatting_ostream< CharT, TraitsT, AllocatorT >::trunc;
  739. template< typename CharT, typename TraitsT, typename AllocatorT >
  740. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::seekdir basic_formatting_ostream< CharT, TraitsT, AllocatorT >::beg;
  741. template< typename CharT, typename TraitsT, typename AllocatorT >
  742. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::seekdir basic_formatting_ostream< CharT, TraitsT, AllocatorT >::cur;
  743. template< typename CharT, typename TraitsT, typename AllocatorT >
  744. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::seekdir basic_formatting_ostream< CharT, TraitsT, AllocatorT >::end;
  745. template< typename CharT, typename TraitsT, typename AllocatorT >
  746. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::event basic_formatting_ostream< CharT, TraitsT, AllocatorT >::erase_event;
  747. template< typename CharT, typename TraitsT, typename AllocatorT >
  748. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::event basic_formatting_ostream< CharT, TraitsT, AllocatorT >::imbue_event;
  749. template< typename CharT, typename TraitsT, typename AllocatorT >
  750. BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::event basic_formatting_ostream< CharT, TraitsT, AllocatorT >::copyfmt_event;
  751. template< typename CharT, typename TraitsT, typename AllocatorT >
  752. void basic_formatting_ostream< CharT, TraitsT, AllocatorT >::aligned_write(const char_type* p, std::streamsize size)
  753. {
  754. typename string_type::size_type const alignment_size =
  755. static_cast< typename string_type::size_type >(m_stream.width() - size);
  756. const bool align_left = (m_stream.flags() & ostream_type::adjustfield) == ostream_type::left;
  757. if (align_left)
  758. {
  759. m_streambuf.append(p, static_cast< std::size_t >(size));
  760. m_streambuf.append(alignment_size, m_stream.fill());
  761. }
  762. else
  763. {
  764. m_streambuf.append(alignment_size, m_stream.fill());
  765. m_streambuf.append(p, static_cast< std::size_t >(size));
  766. }
  767. }
  768. template< typename CharT, typename TraitsT, typename AllocatorT >
  769. template< typename OtherCharT >
  770. void basic_formatting_ostream< CharT, TraitsT, AllocatorT >::aligned_write(const OtherCharT* p, std::streamsize size)
  771. {
  772. string_type* const storage = m_streambuf.storage();
  773. typename string_type::size_type const alignment_size =
  774. static_cast< typename string_type::size_type >(m_stream.width() - size);
  775. const bool align_left = (m_stream.flags() & ostream_type::adjustfield) == ostream_type::left;
  776. if (align_left)
  777. {
  778. if (!m_streambuf.storage_overflow())
  779. {
  780. if (!aux::code_convert(p, static_cast< std::size_t >(size), *storage, m_streambuf.max_size(), m_stream.getloc()))
  781. m_streambuf.storage_overflow(true);
  782. }
  783. m_streambuf.append(alignment_size, m_stream.fill());
  784. }
  785. else
  786. {
  787. m_streambuf.append(alignment_size, m_stream.fill());
  788. if (!m_streambuf.storage_overflow())
  789. {
  790. if (!aux::code_convert(p, static_cast< std::size_t >(size), *storage, m_streambuf.max_size(), m_stream.getloc()))
  791. m_streambuf.storage_overflow(true);
  792. }
  793. }
  794. }
  795. // Implementation note: these operators below should be the least attractive for the compiler
  796. // so that user's overloads are chosen, when present. We use function template partial ordering for this purpose.
  797. // We also don't use perfect forwarding for the right hand argument because in this case the generic overload
  798. // would be more preferred than the typical one written by users:
  799. //
  800. // formatting_ostream& operator<< (formatting_ostream& strm, my_type const& arg);
  801. //
  802. // This is because my_type rvalues require adding const to the type, which counts as a conversion that is not required
  803. // if there is a perfect forwarding overload.
  804. template< typename StreamT, typename T >
  805. inline typename boost::log::aux::enable_formatting_ostream_generic_operator< StreamT, T, true, StreamT& >::type
  806. operator<< (StreamT& strm, T value)
  807. {
  808. strm.stream() << value;
  809. return strm;
  810. }
  811. template< typename StreamT, typename T >
  812. inline typename boost::log::aux::enable_formatting_ostream_generic_operator< StreamT, T, false, StreamT& >::type
  813. operator<< (StreamT& strm, T const& value)
  814. {
  815. strm.stream() << value;
  816. return strm;
  817. }
  818. template< typename StreamT, typename T >
  819. inline typename boost::log::aux::enable_formatting_ostream_generic_operator< StreamT, T, false, StreamT& >::type
  820. operator<< (StreamT& strm, T& value)
  821. {
  822. strm.stream() << value;
  823. return strm;
  824. }
  825. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  826. template< typename StreamT, typename T >
  827. inline typename boost::log::aux::enable_formatting_ostream_generic_operator< StreamT, T, true, StreamT& >::type
  828. operator<< (StreamT&& strm, T value)
  829. {
  830. strm.stream() << value;
  831. return strm;
  832. }
  833. template< typename StreamT, typename T >
  834. inline typename boost::log::aux::enable_formatting_ostream_generic_operator< StreamT, T, false, StreamT& >::type
  835. operator<< (StreamT&& strm, T const& value)
  836. {
  837. strm.stream() << value;
  838. return strm;
  839. }
  840. template< typename StreamT, typename T >
  841. inline typename boost::log::aux::enable_formatting_ostream_generic_operator< StreamT, T, false, StreamT& >::type
  842. operator<< (StreamT&& strm, T& value)
  843. {
  844. strm.stream() << value;
  845. return strm;
  846. }
  847. #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  848. BOOST_LOG_CLOSE_NAMESPACE // namespace log
  849. } // namespace boost
  850. #include <boost/log/detail/footer.hpp>
  851. #endif // BOOST_LOG_UTILITY_FORMATTING_OSTREAM_HPP_INCLUDED_