From d17f091b5a753b33fb455e92b590fc9f4e921119 Mon Sep 17 00:00:00 2001 From: Jan-Espen Oversand Date: Sat, 21 Jun 2025 15:28:35 +0200 Subject: [PATCH 1/4] Fix missing std::char_traits (if it is in fact missing). #1812 --- Release/include/cpprest/streams.h | 75 ++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/Release/include/cpprest/streams.h b/Release/include/cpprest/streams.h index b6c3864028..9998a56d96 100644 --- a/Release/include/cpprest/streams.h +++ b/Release/include/cpprest/streams.h @@ -72,18 +72,89 @@ struct Value2StringFormatter } }; +template class DetailCharTraits +{ +public: + using char_type = T; + using int_type = unsigned int; + using off_type = std::streamoff; + using pos_type = std::streampos; + using state_type = mbstate_t; + + static void assign(char_type& r, const char_type& a) noexcept { r = a; } + static char_type to_char_type(int_type c) noexcept { return char_type(c); } + static int_type to_int_type(char_type c) noexcept { return c; } + static bool eq(char_type a, char_type b) noexcept { return a == b; } + static bool lt(char_type a, char_type b) noexcept { return a < b; } + static int compare(const char_type* s1,const char_type* s2,size_t n){ + for (; n--; ++s1, ++s2) { + if (!eq(*s1, *s2)) + return lt(*s1,*s2)?-1:1; + } + return 0; + } + static size_t length(const char_type* s){ + const char_type* p = s; + while (*p) + ++p; + return size_t(p - s); + } + static const char_type* find(const char_type* s,size_t n,const char_type& a){ + for (; n--; ++s) + { + if (eq(*s, a)) + return s; + return nullptr; + } + } + static char_type* move (char_type* r,const char_type* s,size_t n){ + return (char_type*)memmove(r, s, n * sizeof(char_type)); + } + static char_type* copy (char_type* r,const char_type* s,size_t n){ + return (char_type*)memcpy (r, s, n * sizeof(char_type)); + } + static char_type* assign(char_type* r,size_t n,char_type a){ + if (sizeof(char_type) == 1) + { + return (char_type*)memset(r, a, n); + } + else + { + for (char_type *s = r; n--; ++s) + { + *s = a; + } + } + } + static int_type eof() noexcept { return ~0u; } + static int_type not_eof(int_type c) noexcept { return c == eof() ? 0 : c; } +}; + +template struct CanUseStdCharTraits : public std::false_type +{ +public: + typedef DetailCharTraits TraitsType; +}; + +template struct CanUseStdCharTraits::eq(std::declval(), std::declval()))> : public std::true_type +{ +public: + typedef std::char_traits TraitsType; +}; + + template<> struct Value2StringFormatter { template - static std::basic_string format(const T& val) + static std::basic_string::TraitsType> format(const T& val) { std::basic_ostringstream ss; ss << val; return reinterpret_cast(ss.str().c_str()); } - static std::basic_string format(const utf16string& val) + static std::basic_string::TraitsType> format(const utf16string& val) { return format(utility::conversions::utf16_to_utf8(val)); } From 6df13a8c0417ef700c0f164bcd0686ad46f66fd9 Mon Sep 17 00:00:00 2001 From: Jan-Espen Oversand Date: Sun, 29 Jun 2025 10:20:59 +0200 Subject: [PATCH 2/4] Fix compiling (missing std::char_traits) on llvm for tests as well. #1812 --- Release/include/cpprest/astreambuf.h | 7 +- Release/include/cpprest/details/char_traits.h | 92 +++++++++++++++++++ Release/include/cpprest/streams.h | 91 +++--------------- .../functional/streams/memstream_tests.cpp | 15 +-- .../functional/streams/stdstream_tests.cpp | 7 +- 5 files changed, 122 insertions(+), 90 deletions(-) create mode 100644 Release/include/cpprest/details/char_traits.h diff --git a/Release/include/cpprest/astreambuf.h b/Release/include/cpprest/astreambuf.h index 1dcb285ded..176d01728a 100644 --- a/Release/include/cpprest/astreambuf.h +++ b/Release/include/cpprest/astreambuf.h @@ -15,6 +15,7 @@ #include "cpprest/asyncrt_utils.h" #include "cpprest/details/basic_types.h" +#include "cpprest/details/char_traits.h" #include "pplx/pplxtasks.h" #include #include @@ -57,16 +58,16 @@ namespace streams /// The data type of the basic element of the stream. /// template -struct char_traits : std::char_traits<_CharType> +struct char_traits : utility::CanUseStdCharTraits<_CharType>::TraitsType { /// /// Some synchronous functions will return this value if the operation /// requires an asynchronous call in a given situation. /// /// An int_type value which implies that an asynchronous call is required. - static typename std::char_traits<_CharType>::int_type requires_async() + static typename utility::CanUseStdCharTraits<_CharType>::TraitsType::int_type requires_async() { - return std::char_traits<_CharType>::eof() - 1; + return utility::CanUseStdCharTraits<_CharType>::TraitsType::eof() - 1; } }; #if !defined(_WIN32) diff --git a/Release/include/cpprest/details/char_traits.h b/Release/include/cpprest/details/char_traits.h new file mode 100644 index 0000000000..a54740cdac --- /dev/null +++ b/Release/include/cpprest/details/char_traits.h @@ -0,0 +1,92 @@ +// +// Created by sigsegv on 6/28/25. +// + +#ifndef CPPRESTSDK_ROOT_CHAR_TRAITS_H +#define CPPRESTSDK_ROOT_CHAR_TRAITS_H + +#include +#include + +namespace utility { + +namespace detail { + +template class DetailCharTraits +{ +public: + using char_type = T; + using int_type = std::char_traits::int_type; + using off_type = std::streamoff; + using pos_type = std::streampos; + using state_type = mbstate_t; + + static void assign(char_type& r, const char_type& a) noexcept { r = a; } + static char_type to_char_type(int_type c) noexcept { return char_type(c); } + static int_type to_int_type(char_type c) noexcept { return c; } + static bool eq(char_type a, char_type b) noexcept { return a == b; } + static bool lt(char_type a, char_type b) noexcept { return a < b; } + static int compare(const char_type* s1,const char_type* s2,size_t n){ + for (; n--; ++s1, ++s2) { + if (!eq(*s1, *s2)) + return lt(*s1,*s2)?-1:1; + } + return 0; + } + static size_t length(const char_type* s){ + const char_type* p = s; + while (*p) + ++p; + return size_t(p - s); + } + static const char_type* find(const char_type* s,size_t n,const char_type& a){ + for (; n--; ++s) + { + if (eq(*s, a)) + return s; + return nullptr; + } + } + static char_type* move (char_type* r,const char_type* s,size_t n){ + return (char_type*)memmove(r, s, n * sizeof(char_type)); + } + static char_type* copy (char_type* r,const char_type* s,size_t n){ + return (char_type*)memcpy (r, s, n * sizeof(char_type)); + } + static char_type* assign(char_type* r,size_t n,char_type a){ + if (sizeof(char_type) == 1) + { + return (char_type*)memset(r, a, n); + } + else + { + for (char_type *s = r; n--; ++s) + { + *s = a; + } + } + } + static int_type eof() noexcept { return ~0u; } + static int_type not_eof(int_type c) noexcept { return c == eof() ? 0 : c; } +}; + +template struct CanUseStdCharTraits : public std::false_type +{ +public: + typedef DetailCharTraits TraitsType; +}; + +template struct CanUseStdCharTraits::eq(std::declval(), std::declval()))> : public std::true_type +{ +public: + typedef std::char_traits TraitsType; +}; + +} + +template struct CanUseStdCharTraits : detail::CanUseStdCharTraits::type>::type> { +}; + +} + +#endif // CPPRESTSDK_ROOT_CHAR_TRAITS_H diff --git a/Release/include/cpprest/streams.h b/Release/include/cpprest/streams.h index 9998a56d96..dda7289bbe 100644 --- a/Release/include/cpprest/streams.h +++ b/Release/include/cpprest/streams.h @@ -16,6 +16,7 @@ #define CASA_STREAMS_H #include "cpprest/astreambuf.h" +#include "cpprest/details/char_traits.h" #include #include @@ -64,97 +65,31 @@ template struct Value2StringFormatter { template - static std::basic_string format(const T& val) + static std::basic_string::TraitsType> format(const T& val) { - std::basic_ostringstream ss; + std::basic_ostringstream::TraitsType> ss; ss << val; return ss.str(); } }; -template class DetailCharTraits -{ -public: - using char_type = T; - using int_type = unsigned int; - using off_type = std::streamoff; - using pos_type = std::streampos; - using state_type = mbstate_t; - - static void assign(char_type& r, const char_type& a) noexcept { r = a; } - static char_type to_char_type(int_type c) noexcept { return char_type(c); } - static int_type to_int_type(char_type c) noexcept { return c; } - static bool eq(char_type a, char_type b) noexcept { return a == b; } - static bool lt(char_type a, char_type b) noexcept { return a < b; } - static int compare(const char_type* s1,const char_type* s2,size_t n){ - for (; n--; ++s1, ++s2) { - if (!eq(*s1, *s2)) - return lt(*s1,*s2)?-1:1; - } - return 0; - } - static size_t length(const char_type* s){ - const char_type* p = s; - while (*p) - ++p; - return size_t(p - s); - } - static const char_type* find(const char_type* s,size_t n,const char_type& a){ - for (; n--; ++s) - { - if (eq(*s, a)) - return s; - return nullptr; - } - } - static char_type* move (char_type* r,const char_type* s,size_t n){ - return (char_type*)memmove(r, s, n * sizeof(char_type)); - } - static char_type* copy (char_type* r,const char_type* s,size_t n){ - return (char_type*)memcpy (r, s, n * sizeof(char_type)); - } - static char_type* assign(char_type* r,size_t n,char_type a){ - if (sizeof(char_type) == 1) - { - return (char_type*)memset(r, a, n); - } - else - { - for (char_type *s = r; n--; ++s) - { - *s = a; - } - } - } - static int_type eof() noexcept { return ~0u; } - static int_type not_eof(int_type c) noexcept { return c == eof() ? 0 : c; } -}; - -template struct CanUseStdCharTraits : public std::false_type -{ -public: - typedef DetailCharTraits TraitsType; -}; - -template struct CanUseStdCharTraits::eq(std::declval(), std::declval()))> : public std::true_type -{ -public: - typedef std::char_traits TraitsType; -}; - - template<> struct Value2StringFormatter { template - static std::basic_string::TraitsType> format(const T& val) + static std::basic_string::TraitsType> format(const T& val) { std::basic_ostringstream ss; ss << val; return reinterpret_cast(ss.str().c_str()); } - static std::basic_string::TraitsType> format(const utf16string& val) + template <> std::basic_string::TraitsType> format::TraitsType>>(const std::basic_string::TraitsType> &val) + { + return format(reinterpret_cast &>(val)); + } + + static std::basic_string::TraitsType> format(const utf16string& val) { return format(utility::conversions::utf16_to_utf8(val)); } @@ -173,7 +108,7 @@ template class basic_ostream { public: - typedef char_traits traits; + typedef typename utility::CanUseStdCharTraits::TraitsType traits; typedef typename traits::int_type int_type; typedef typename traits::pos_type pos_type; typedef typename traits::off_type off_type; @@ -333,7 +268,7 @@ class basic_ostream /// Write the specified string to the output stream. /// /// Input string. - pplx::task print(const std::basic_string& str) const + pplx::task print(const std::basic_string& str) const { pplx::task result; if (!_verify_and_return_task(details::_out_stream_msg, result)) return result; @@ -344,7 +279,7 @@ class basic_ostream } else { - auto sharedStr = std::make_shared>(str); + auto sharedStr = std::make_shared>(str); return helper()->m_buffer.putn_nocopy(sharedStr->c_str(), sharedStr->size()).then([sharedStr](size_t size) { return size; }); diff --git a/Release/tests/functional/streams/memstream_tests.cpp b/Release/tests/functional/streams/memstream_tests.cpp index 3bdbd6812a..b47c50c9b4 100644 --- a/Release/tests/functional/streams/memstream_tests.cpp +++ b/Release/tests/functional/streams/memstream_tests.cpp @@ -8,6 +8,7 @@ * * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ****/ +#include "cpprest/details/char_traits.h" #include "stdafx.h" #if defined(__cplusplus_winrt) #include @@ -32,7 +33,7 @@ void streambuf_putc(StreamBufferType& wbuf) { VERIFY_IS_TRUE(wbuf.can_write()); - std::basic_string s; + std::basic_string::TraitsType> s; s.push_back((typename StreamBufferType::char_type)0); s.push_back((typename StreamBufferType::char_type)1); s.push_back((typename StreamBufferType::char_type)2); @@ -137,7 +138,7 @@ void streambuf_putn(StreamBufferType& wbuf) { VERIFY_IS_TRUE(wbuf.can_write()); - std::basic_string s; + std::basic_string::TraitsType> s; s.push_back((typename StreamBufferType::char_type)0); s.push_back((typename StreamBufferType::char_type)1); s.push_back((typename StreamBufferType::char_type)2); @@ -169,7 +170,7 @@ void streambuf_putn(concurrency::streams::rawptr_buffer& wbuf) typedef concurrency::streams::rawptr_buffer StreamBufferType; - std::basic_string s; + std::basic_string::TraitsType> s; s.push_back((CharType)0); s.push_back((CharType)1); s.push_back((CharType)2); @@ -198,7 +199,7 @@ void streambuf_putn(concurrency::streams::container_buffer& wbuf typedef concurrency::streams::container_buffer StreamBufferType; typedef typename concurrency::streams::container_buffer::char_type CharType; - std::basic_string s; + std::basic_string::TraitsType> s; s.push_back((CharType)0); s.push_back((CharType)1); s.push_back((CharType)2); @@ -553,7 +554,7 @@ void streambuf_putn_getn(StreamBufferType& rwbuf) VERIFY_IS_TRUE(rwbuf.can_read()); VERIFY_IS_TRUE(rwbuf.can_write()); VERIFY_IS_FALSE(rwbuf.is_eof()); - std::basic_string s; + std::basic_string::TraitsType> s; s.push_back((typename StreamBufferType::char_type)0); s.push_back((typename StreamBufferType::char_type)1); s.push_back((typename StreamBufferType::char_type)2); @@ -684,7 +685,7 @@ void streambuf_close_read_with_pending_read(StreamBufferType& rwbuf) VERIFY_IS_TRUE(rwbuf.can_write()); // Write 4 characters - std::basic_string s; + std::basic_string::TraitsType> s; s.push_back((typename StreamBufferType::char_type)0); s.push_back((typename StreamBufferType::char_type)1); s.push_back((typename StreamBufferType::char_type)2); @@ -726,7 +727,7 @@ void streambuf_close_write_with_pending_read(StreamBufferType& rwbuf) VERIFY_IS_TRUE(rwbuf.can_write()); // Write 4 characters - std::basic_string s; + std::basic_string::TraitsType> s; s.push_back((typename StreamBufferType::char_type)0); s.push_back((typename StreamBufferType::char_type)1); s.push_back((typename StreamBufferType::char_type)2); diff --git a/Release/tests/functional/streams/stdstream_tests.cpp b/Release/tests/functional/streams/stdstream_tests.cpp index 34b9b3af12..c294b02d0e 100644 --- a/Release/tests/functional/streams/stdstream_tests.cpp +++ b/Release/tests/functional/streams/stdstream_tests.cpp @@ -13,6 +13,7 @@ #include "cpprest/filestream.h" #include "cpprest/producerconsumerstream.h" #include "cpprest/rawptrstream.h" +#include "cpprest/details/char_traits.h" #if (!defined(_WIN32) || !defined(CPPREST_EXCLUDE_WEBSOCKETS)) && !defined(__cplusplus_winrt) #include @@ -303,7 +304,8 @@ SUITE(stdstreambuf_tests) const std::streamsize iterations = 100; - const std::string the_alphabet("abcdefghijklmnopqrstuvwxyz"); + const char *the_alphabet_characters = "abcdefghijklmnopqrstuvwxyz"; + const std::basic_string::TraitsType> the_alphabet(reinterpret_cast(the_alphabet_characters)); auto writer = pplx::create_task([ostream, iterations, the_alphabet]() { auto os = ostream; @@ -341,7 +343,8 @@ SUITE(stdstreambuf_tests) const std::streamsize iterations = 100; - const std::string the_alphabet("abcdefghijklmnopqrstuvwxyz"); + const char *the_alphabet_chars = "abcdefghijklmnopqrstuvwxyz"; + const std::basic_string::TraitsType> the_alphabet(reinterpret_cast(the_alphabet_chars)); auto writer = pplx::create_task([ostream, iterations, the_alphabet]() { auto os = ostream; From 4188ad89b2cf2e8de3cc3513adcf400fbfdc5ce7 Mon Sep 17 00:00:00 2001 From: Jan-Espen Oversand Date: Sun, 29 Jun 2025 18:53:31 +0200 Subject: [PATCH 3/4] Adjustments to avoid breaking compiling with gcc when fixing compiling with llvm. #1812 --- Release/include/cpprest/astreambuf.h | 43 ++++--------------- Release/include/cpprest/details/char_traits.h | 12 +++++- Release/include/cpprest/streams.h | 30 ++++++++++--- 3 files changed, 42 insertions(+), 43 deletions(-) diff --git a/Release/include/cpprest/astreambuf.h b/Release/include/cpprest/astreambuf.h index 176d01728a..fab450b0eb 100644 --- a/Release/include/cpprest/astreambuf.h +++ b/Release/include/cpprest/astreambuf.h @@ -57,6 +57,8 @@ namespace streams /// /// The data type of the basic element of the stream. /// +namespace detail +{ template struct char_traits : utility::CanUseStdCharTraits<_CharType>::TraitsType { @@ -70,42 +72,13 @@ struct char_traits : utility::CanUseStdCharTraits<_CharType>::TraitsType return utility::CanUseStdCharTraits<_CharType>::TraitsType::eof() - 1; } }; +} +template struct char_traits : detail::char_traits<_CharType> { +}; #if !defined(_WIN32) -template<> -struct char_traits : private std::char_traits -{ -public: - typedef unsigned char char_type; - - using std::char_traits::eof; - using std::char_traits::int_type; - using std::char_traits::off_type; - using std::char_traits::pos_type; - - static size_t length(const unsigned char* str) - { - return std::char_traits::length(reinterpret_cast(str)); - } - - static void assign(unsigned char& left, const unsigned char& right) { left = right; } - static unsigned char* assign(unsigned char* left, size_t n, unsigned char value) - { - return reinterpret_cast( - std::char_traits::assign(reinterpret_cast(left), n, static_cast(value))); - } - - static unsigned char* copy(unsigned char* left, const unsigned char* right, size_t n) - { - return reinterpret_cast( - std::char_traits::copy(reinterpret_cast(left), reinterpret_cast(right), n)); - } - - static unsigned char* move(unsigned char* left, const unsigned char* right, size_t n) - { - return reinterpret_cast( - std::char_traits::move(reinterpret_cast(left), reinterpret_cast(right), n)); - } - +template <> struct char_traits : detail::char_traits { + typedef typename std::char_traits::int_type int_type; + static int_type eof() { return std::char_traits::eof(); } static int_type requires_async() { return eof() - 1; } }; #endif diff --git a/Release/include/cpprest/details/char_traits.h b/Release/include/cpprest/details/char_traits.h index a54740cdac..6be58c6e84 100644 --- a/Release/include/cpprest/details/char_traits.h +++ b/Release/include/cpprest/details/char_traits.h @@ -12,11 +12,21 @@ namespace utility { namespace detail { +template struct IntTypeFor { + typedef typename std::conditional::value, unsigned long long int, long long int>::type type; +}; +template <> struct IntTypeFor { + typedef typename std::char_traits::int_type type; +}; +template <> struct IntTypeFor { + typedef typename std::make_unsigned::int_type>::type type; +}; + template class DetailCharTraits { public: using char_type = T; - using int_type = std::char_traits::int_type; + using int_type = typename IntTypeFor::type; using off_type = std::streamoff; using pos_type = std::streampos; using state_type = mbstate_t; diff --git a/Release/include/cpprest/streams.h b/Release/include/cpprest/streams.h index dda7289bbe..d254089efb 100644 --- a/Release/include/cpprest/streams.h +++ b/Release/include/cpprest/streams.h @@ -73,20 +73,36 @@ struct Value2StringFormatter } }; -template<> -struct Value2StringFormatter +template +struct Value2StringFormatterUint8Format { - template - static std::basic_string::TraitsType> format(const T& val) + std::basic_string::TraitsType> operator () (const T& val) { std::basic_ostringstream ss; ss << val; return reinterpret_cast(ss.str().c_str()); } +}; - template <> std::basic_string::TraitsType> format::TraitsType>>(const std::basic_string::TraitsType> &val) +template <> +struct Value2StringFormatterUint8Format::TraitsType>> +{ + std::basic_string::TraitsType> operator () ( + const std::basic_string::TraitsType>& val) { - return format(reinterpret_cast &>(val)); + Value2StringFormatterUint8Format> format; + return format(reinterpret_cast&>(val)); + } +}; + +template<> +struct Value2StringFormatter +{ + template + static std::basic_string::TraitsType> format(const T& val) + { + Value2StringFormatterUint8Format format; + return format(val); } static std::basic_string::TraitsType> format(const utf16string& val) @@ -108,7 +124,7 @@ template class basic_ostream { public: - typedef typename utility::CanUseStdCharTraits::TraitsType traits; + typedef char_traits traits; typedef typename traits::int_type int_type; typedef typename traits::pos_type pos_type; typedef typename traits::off_type off_type; From 32b322b564e5e540ff02393ffe3bd3bade8d299c Mon Sep 17 00:00:00 2001 From: Jan-Espen Oversand Date: Tue, 1 Jul 2025 07:04:03 +0200 Subject: [PATCH 4/4] Testing with gcc revealed difficulties reaching the actual implementation function of print/format through the specializations leading to infinite recursion. Fixes streams_test broken by the char_traits fixes. Unfortunately reuires some extra string copying because the std streams library really really doesn't work well on anything but char (signed) types on gcc and llvm, so general advice seems to be to convert to char on the way in and back to unsigned on the way out if one really need the std streams library to work on unsigned types. #1812 --- Release/include/cpprest/streams.h | 76 ++++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 16 deletions(-) diff --git a/Release/include/cpprest/streams.h b/Release/include/cpprest/streams.h index d254089efb..73cfcc480a 100644 --- a/Release/include/cpprest/streams.h +++ b/Release/include/cpprest/streams.h @@ -61,22 +61,66 @@ class basic_istream_helper concurrency::streams::streambuf m_buffer; }; -template +template::TraitsType> struct Value2StringFormatter { - template - static std::basic_string::TraitsType> format(const T& val) + struct SanitizeInput { - std::basic_ostringstream::TraitsType> ss; - ss << val; - return ss.str(); + const std::basic_string &operator () (const std::basic_string &input) + { + return input; + } + template std::basic_string operator () (const std::basic_string &input) + { + return {reinterpret_cast(input.c_str()), input.size()}; + } + const char *operator () (const char *input) { + return input; + } + const char *operator () (const unsigned char *input) + { + return reinterpret_cast(input); + } + template T operator () (T input) + { + return input; + } + }; + struct GenerateFormatOutput + { + std::basic_string &&operator() (std::basic_string &&result) + { + return std::move(result); + } + std::basic_string operator() (const std::basic_string &intermediate) + { + return {reinterpret_cast(intermediate.c_str()), intermediate.size()}; + } + }; + template + static std::basic_string format(const T& val) + { + typename std::conditional< + sizeof(CharType) == 1, + std::basic_ostringstream, + std::basic_ostringstream::type> + >::type ss; + SanitizeInput sanitizer; + ss << sanitizer(val); + typename std::conditional< + sizeof(CharType) == 1, + std::basic_string, + std::basic_string::type> + >::type str = ss.str(); + GenerateFormatOutput generateFormatOutput; + return generateFormatOutput(std::move(str)); } }; -template +template struct Value2StringFormatterUint8Format { - std::basic_string::TraitsType> operator () (const T& val) + std::basic_string operator () (const T& val) { std::basic_ostringstream ss; ss << val; @@ -84,13 +128,13 @@ struct Value2StringFormatterUint8Format } }; -template <> -struct Value2StringFormatterUint8Format::TraitsType>> +template +struct Value2StringFormatterUint8Format> { - std::basic_string::TraitsType> operator () ( + std::basic_string operator () ( const std::basic_string::TraitsType>& val) { - Value2StringFormatterUint8Format> format; + Value2StringFormatterUint8Format> format; return format(reinterpret_cast&>(val)); } }; @@ -98,10 +142,10 @@ struct Value2StringFormatterUint8Format struct Value2StringFormatter { - template - static std::basic_string::TraitsType> format(const T& val) + template ::TraitsType> + static std::basic_string format(const T& val) { - Value2StringFormatterUint8Format format; + Value2StringFormatterUint8Format format; return format(val); } @@ -316,7 +360,7 @@ class basic_ostream if (!_verify_and_return_task(details::_out_stream_msg, result)) return result; // TODO in the future this could be improved to have Value2StringFormatter avoid another unnecessary copy // by putting the string on the heap before calling the print string overload. - return print(details::Value2StringFormatter::format(val)); + return print(details::Value2StringFormatter::format(val)); } ///