| 318 | /// conversions. |
| 319 | template<typename T> |
| 320 | inline void formatValue(std::ostream& out, const char* /*fmtBegin*/, |
| 321 | const char* fmtEnd, int ntrunc, const T& value) |
| 322 | { |
| 323 | #ifndef TINYFORMAT_ALLOW_WCHAR_STRINGS |
| 324 | // Since we don't support printing of wchar_t using "%ls", make it fail at |
| 325 | // compile time in preference to printing as a void* at runtime. |
| 326 | typedef typename detail::is_wchar<T>::tinyformat_wchar_is_not_supported DummyType; |
| 327 | (void) DummyType(); // avoid unused type warning with gcc-4.8 |
| 328 | #endif |
| 329 | // The mess here is to support the %c and %p conversions: if these |
| 330 | // conversions are active we try to convert the type to a char or const |
| 331 | // void* respectively and format that instead of the value itself. For the |
| 332 | // %p conversion it's important to avoid dereferencing the pointer, which |
| 333 | // could otherwise lead to a crash when printing a dangling (const char*). |
| 334 | const bool canConvertToChar = detail::is_convertible<T,char>::value; |
| 335 | const bool canConvertToVoidPtr = detail::is_convertible<T, const void*>::value; |
| 336 | if (canConvertToChar && *(fmtEnd-1) == 'c') |
| 337 | detail::formatValueAsType<T, char>::invoke(out, value); |
| 338 | else if (canConvertToVoidPtr && *(fmtEnd-1) == 'p') |
| 339 | detail::formatValueAsType<T, const void*>::invoke(out, value); |
| 340 | #ifdef TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND |
| 341 | else if (detail::formatZeroIntegerWorkaround<T>::invoke(out, value)) /**/; |
| 342 | #endif |
| 343 | else if (ntrunc >= 0) { |
| 344 | // Take care not to overread C strings in truncating conversions like |
| 345 | // "%.4s" where at most 4 characters may be read. |
| 346 | detail::formatTruncated(out, value, ntrunc); |
| 347 | } |
| 348 | else |
| 349 | out << value; |
| 350 | } |
| 351 | |
| 352 | |
| 353 | // Overloaded version for char types to support printing as an integer |
nothing calls this directly
no test coverage detected