compilerplugins/clang/stringadd.cxx             |    1 
 compilerplugins/clang/stringconcatauto.cxx      |    8 
 compilerplugins/clang/stringview.cxx            |    7 
 compilerplugins/clang/test/stringconcatauto.cxx |   12 
 compilerplugins/clang/test/stringview.cxx       |    4 
 include/rtl/strbuf.hxx                          |   19 -
 include/rtl/string.hxx                          |   34 --
 include/rtl/stringconcat.hxx                    |  396 ++++++++----------------
 include/rtl/ustrbuf.hxx                         |   17 -
 include/rtl/ustring.hxx                         |   38 --
 10 files changed, 210 insertions(+), 326 deletions(-)

New commits:
commit af2879e434fa0dc6b2a626617ed865e4f66eb5ad
Author:     Mike Kaganski <[email protected]>
AuthorDate: Wed Oct 12 16:23:33 2022 +0300
Commit:     Mike Kaganski <[email protected]>
CommitDate: Thu Oct 13 07:18:41 2022 +0200

    Deduplicate stringconcat more
    
    In the process, drop ToStringHelper::allowO(U)StringConcat, because
    we can deduce this information from ToStringHelper's addData itself.
    To do that, addData was converted to ToStringHelper::operator(),
    which allows to use std::is_invocable_v on the helper class.
    
    Change-Id: Ic77878ca0ff65ada8c0a942191bc11de15b9ad2a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/141254
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <[email protected]>

diff --git a/compilerplugins/clang/stringadd.cxx 
b/compilerplugins/clang/stringadd.cxx
index 339192a78687..9254e9190ed5 100644
--- a/compilerplugins/clang/stringadd.cxx
+++ b/compilerplugins/clang/stringadd.cxx
@@ -233,6 +233,7 @@ bool 
StringAdd::VisitCXXOperatorCallExpr(CXXOperatorCallExpr const* operatorCall
     auto tc = 
loplugin::TypeCheck(operatorCall->getType()->getUnqualifiedDesugaredType());
     if (!tc.Struct("OUStringConcat").Namespace("rtl").GlobalNamespace()
         && !tc.Struct("OStringConcat").Namespace("rtl").GlobalNamespace()
+        && !tc.Struct("StringConcat").Namespace("rtl").GlobalNamespace()
         && !tc.Class("OUString").Namespace("rtl").GlobalNamespace()
         && !tc.Class("OString").Namespace("rtl").GlobalNamespace())
         return true;
diff --git a/compilerplugins/clang/stringconcatauto.cxx 
b/compilerplugins/clang/stringconcatauto.cxx
index 561aedec8070..02517a4db0ba 100644
--- a/compilerplugins/clang/stringconcatauto.cxx
+++ b/compilerplugins/clang/stringconcatauto.cxx
@@ -83,10 +83,10 @@ bool StringConcatAuto::checkDecl( const DeclaratorDecl* 
decl, QualType type, con
         return true;
     auto const tc = loplugin::TypeCheck( 
type.getNonReferenceType().getCanonicalType());
     const char* typeString = nullptr;
-    if( tc.Struct("OUStringConcat").Namespace("rtl").GlobalNamespace())
-        typeString = "OUString";
-    else if( tc.Struct("OStringConcat").Namespace("rtl").GlobalNamespace())
-        typeString = "OString";
+    if( tc.Struct("StringConcat").Namespace("rtl").GlobalNamespace())
+        typeString = "O(U)String";
+    else if( tc.Struct("StringNumber").Namespace("rtl").GlobalNamespace())
+        typeString = "O(U)String";
     else if( tc.Struct("OUStringNumber").Namespace("rtl").GlobalNamespace())
         typeString = "OUString";
     else if( tc.Struct("OStringNumber").Namespace("rtl").GlobalNamespace())
diff --git a/compilerplugins/clang/stringview.cxx 
b/compilerplugins/clang/stringview.cxx
index c1606908dbc7..16e53b1c12e9 100644
--- a/compilerplugins/clang/stringview.cxx
+++ b/compilerplugins/clang/stringview.cxx
@@ -206,6 +206,10 @@ void StringView::handleCXXConstructExpr(CXXConstructExpr 
const* expr)
                        .Class("OUStringLiteral")
                        .Namespace("rtl")
                        .GlobalNamespace()
+                || tc.RvalueReference()
+                       .Struct("StringNumberBase")
+                       .Namespace("rtl")
+                       .GlobalNamespace()
                 || 
tc.RvalueReference().Struct("OStringNumber").Namespace("rtl").GlobalNamespace()
                 || 
tc.RvalueReference().Struct("OUStringNumber").Namespace("rtl").GlobalNamespace()
                 || tc.ClassOrStruct("basic_string_view").StdNamespace())
@@ -214,7 +218,8 @@ void StringView::handleCXXConstructExpr(CXXConstructExpr 
const* expr)
                 break;
             }
             if 
(tc.RvalueReference().Struct("OStringConcat").Namespace("rtl").GlobalNamespace()
-                || 
tc.RvalueReference().Struct("OUStringConcat").Namespace("rtl").GlobalNamespace())
+                || 
tc.RvalueReference().Struct("OUStringConcat").Namespace("rtl").GlobalNamespace()
+                || 
tc.RvalueReference().Struct("StringConcat").Namespace("rtl").GlobalNamespace())
             {
                 argType = expr->getArg(0)->IgnoreImplicit()->getType();
                 extra = ViaConcatenation;
diff --git a/compilerplugins/clang/test/stringconcatauto.cxx 
b/compilerplugins/clang/test/stringconcatauto.cxx
index dc450503d25e..72044f80b150 100644
--- a/compilerplugins/clang/test/stringconcatauto.cxx
+++ b/compilerplugins/clang/test/stringconcatauto.cxx
@@ -15,14 +15,14 @@ void foo()
 {
     auto str1 = "str1" + OUString::number(10);
     // expected-error-re@-1 {{creating a variable of type {{.+}} will make it 
reference temporaries}}
-    // expected-note@-2 {{use OUString instead}}
+    // expected-note@-2 {{use O(U)String instead}}
     OUString str2 = "str2" + OUString::number(20) + "ing";
     const auto& str3 = "str3" + OUString::number(30);
     // expected-error-re@-1 {{creating a variable of type {{.+}} will make it 
reference temporaries}}
-    // expected-note@-2 {{use OUString instead}}
+    // expected-note@-2 {{use O(U)String instead}}
     const auto str4 = "str4" + OString::number(40);
     // expected-error-re@-1 {{creating a variable of type {{.+}} will make it 
reference temporaries}}
-    // expected-note@-2 {{use OString instead}}
+    // expected-note@-2 {{use O(U)String instead}}
     auto str5 = OUString::number(50);
     // expected-error-re@-1 {{creating a variable of type 
'{{(rtl::)?}}OUStringNumber<{{.*}}>' will make it reference temporaries}}
     // expected-note@-2 {{use OUString instead}}
@@ -37,7 +37,7 @@ struct A
 {
     auto bar()
     // expected-error-re@-1 {{returning a variable of type {{.+}} will make it 
reference temporaries}}
-    // expected-note@-2 {{use OString instead}}
+    // expected-note@-2 {{use O(U)String instead}}
     {
         return "bar" + OString::number(110);
     }
@@ -53,8 +53,8 @@ template <typename T> void fun(const T& par)
 // parameters are without warnings
 {
     const T& var = par;
-    // expected-error-re@-1 {{creating a variable of type 'const 
rtl::OUStringConcat<{{.*}}> &' will make it reference temporaries}}
-    // expected-note@-2 {{use OUString instead}}
+    // expected-error-re@-1 {{creating a variable of type 'const 
rtl::StringConcat<{{.*}}> &' will make it reference temporaries}}
+    // expected-note@-2 {{use O(U)String instead}}
     (void)var;
 }
 
diff --git a/compilerplugins/clang/test/stringview.cxx 
b/compilerplugins/clang/test/stringview.cxx
index f578a5f50e8d..cd59f6c3c73a 100644
--- a/compilerplugins/clang/test/stringview.cxx
+++ b/compilerplugins/clang/test/stringview.cxx
@@ -167,7 +167,7 @@ void f5(char const* s1, sal_Int32 n1, char16_t const* s2, 
sal_Int32 n2, OString
     call_view(OString(std::string_view("foo")));
     // expected-error-re@+1 {{instead of an '{{(rtl::)?}}OString' constructed 
from a 'OStringNumber<int>', pass a 'std::string_view' [loplugin:stringview]}}
     call_view(OString(OString::number(0)));
-    // expected-error-re@+1 {{instead of an '{{(rtl::)?}}OString' constructed 
from a 'typename std::enable_if_t<ToStringHelper<OString>::allowOStringConcat 
&& ToStringHelper<OString>::allowOStringConcat, OStringConcat<OString, 
OString>{{ ?}}>' (aka 'rtl::OStringConcat<rtl::OString, rtl::OString>'), pass a 
'std::string_view' via 'rtl::Concat2View' [loplugin:stringview]}}
+    // expected-error-re@+1 {{instead of an '{{(rtl::)?}}OString' constructed 
from a 'OStringConcat<rtl::OString, rtl::OString>' (aka 'StringConcat<char, 
rtl::OString, rtl::OString>'), pass a 'std::string_view' via 'rtl::Concat2View' 
[loplugin:stringview]}}
     call_view(OString(s3 + s3));
     // expected-error-re@+1 {{instead of an '{{(rtl::)?}}OUString', pass a 
'std::u16string_view' [loplugin:stringview]}}
     call_view(OUString());
@@ -192,7 +192,7 @@ void f5(char const* s1, sal_Int32 n1, char16_t const* s2, 
sal_Int32 n2, OString
     call_view(OUString(std::u16string_view(u"foo")));
     // expected-error-re@+1 {{instead of an '{{(rtl::)?}}OUString' constructed 
from a 'OUStringNumber<int>', pass a 'std::u16string_view' 
[loplugin:stringview]}}
     call_view(OUString(OUString::number(0)));
-    // expected-error-re@+1 {{instead of an '{{(rtl::)?}}OUString' constructed 
from a 'typename std::enable_if_t<ToStringHelper<OUString>::allowOUStringConcat 
&& ToStringHelper<OUString>::allowOUStringConcat, OUStringConcat<OUString, 
OUString>{{ ?}}>' (aka 'rtl::OUStringConcat<rtl::OUString, rtl::OUString>'), 
pass a 'std::u16string_view' via 'rtl::Concat2View' [loplugin:stringview]}}
+    // expected-error-re@+1 {{instead of an '{{(rtl::)?}}OUString' constructed 
from a 'OUStringConcat<rtl::OUString, rtl::OUString>' (aka 
'StringConcat<char16_t, rtl::OUString, rtl::OUString>'), pass a 
'std::u16string_view' via 'rtl::Concat2View' [loplugin:stringview]}}
     call_view(OUString(s4 + s4));
 
     (void)(s3 == l1);
diff --git a/include/rtl/strbuf.hxx b/include/rtl/strbuf.hxx
index 5917c1812e9c..dbdcd7fea39a 100644
--- a/include/rtl/strbuf.hxx
+++ b/include/rtl/strbuf.hxx
@@ -246,9 +246,9 @@ public:
      @overload
      @internal
     */
-    template< typename T >
-    OStringBuffer( OStringNumber< T >&& n )
-        : OStringBuffer( OString( n ))
+    template< typename T, std::size_t N >
+    OStringBuffer( StringNumberBase< char, T, N >&& n )
+        : OStringBuffer( n.buf, n.length)
     {}
 #endif
 
@@ -334,8 +334,8 @@ public:
     }
 
     /** @overload @internal */
-    template<typename T>
-    OStringBuffer & operator =(OStringNumber<T> && n)
+    template<typename T, std::size_t N>
+    OStringBuffer & operator =(StringNumberBase<char, T, N> && n)
     {
         *this = OStringBuffer( std::move ( n ));
         return *this;
@@ -618,8 +618,8 @@ public:
      @overload
      @internal
     */
-    template< typename T >
-    OStringBuffer& append( OStringNumber< T >&& c )
+    template< typename T, std::size_t N >
+    OStringBuffer& append( StringNumberBase< char, T, N >&& c )
     {
         return append( c.buf, c.length );
     }
@@ -1106,11 +1106,8 @@ private:
 template<> struct ToStringHelper<OStringBuffer> {
     static std::size_t length(OStringBuffer const & s) { return s.getLength(); 
}
 
-    static char * addData(char * buffer, OStringBuffer const & s) 
SAL_RETURNS_NONNULL
+    char * operator()(char * buffer, OStringBuffer const & s) const 
SAL_RETURNS_NONNULL
     { return addDataHelper(buffer, s.getStr(), s.getLength()); }
-
-    static constexpr bool allowOStringConcat = true;
-    static constexpr bool allowOUStringConcat = false;
 };
 #endif
 
diff --git a/include/rtl/string.hxx b/include/rtl/string.hxx
index 0e0c3c75d5a9..3d9ef8ff9aa3 100644
--- a/include/rtl/string.hxx
+++ b/include/rtl/string.hxx
@@ -394,8 +394,8 @@ public:
      @overload
      @internal
     */
-    template< typename T >
-    OString( OStringNumber< T >&& n )
+    template< typename T, std::size_t N >
+    OString( StringNumberBase< char, T, N >&& n )
         : OString( n.buf, n.length )
     {}
 #endif
@@ -548,12 +548,12 @@ public:
      @overload
      @internal
     */
-    template< typename T >
-    OString& operator+=( OStringNumber< T >&& n ) & {
+    template< typename T, std::size_t N >
+    OString& operator+=( StringNumberBase< char, T, N >&& n ) & {
         return operator +=(std::string_view(n.buf, n.length));
     }
-    template<typename T> void operator +=(
-        OStringNumber<T> &&) && = delete;
+    template<typename T, std::size_t N> void operator +=(
+        StringNumberBase<char, T, N> &&) && = delete;
 #endif
 
     /**
@@ -2154,16 +2154,14 @@ public:
     //
     // would not compile):
     template<typename T> [[nodiscard]] static
-    typename std::enable_if_t<
-        ToStringHelper<T>::allowOStringConcat, 
OStringConcat<OStringConcatMarker, T>>
+    OStringConcat<OStringConcatMarker, T>
     Concat(T const & value) { return OStringConcat<OStringConcatMarker, T>({}, 
value); }
 
     // This overload is needed so that an argument of type 'char const[N]' 
ends up as
     // 'OStringConcat<rtl::OStringConcatMarker, char const[N]>' rather than as
     // 'OStringConcat<rtl::OStringConcatMarker, char[N]>':
     template<typename T, std::size_t N> [[nodiscard]] static
-    typename std::enable_if_t<
-        ToStringHelper<T[N]>::allowOStringConcat, 
OStringConcat<OStringConcatMarker, T[N]>>
+    OStringConcat<OStringConcatMarker, T[N]>
     Concat(T (& value)[N]) { return OStringConcat<OStringConcatMarker, 
T[N]>({}, value); }
 #endif
 };
@@ -2188,24 +2186,20 @@ inline bool operator !=(StringConcatenation<char> const 
& lhs, OString const & r
 */
 template<>
 struct ToStringHelper< OString >
-    {
+{
     static std::size_t length( const OString& s ) { return s.getLength(); }
-    static char* addData( char* buffer, const OString& s ) { return 
addDataHelper( buffer, s.getStr(), s.getLength()); }
-    static const bool allowOStringConcat = true;
-    static const bool allowOUStringConcat = false;
-    };
+    char* operator()( char* buffer, const OString& s ) const { return 
addDataHelper( buffer, s.getStr(), s.getLength()); }
+};
 
 /**
  @internal
 */
 template<std::size_t N>
 struct ToStringHelper< OStringLiteral<N> >
-    {
+{
     static constexpr std::size_t length( const OStringLiteral<N>& str ) { 
return str.getLength(); }
-    static char* addData( char* buffer, const OStringLiteral<N>& str ) { 
return addDataHelper( buffer, str.getStr(), str.getLength() ); }
-    static const bool allowOStringConcat = true;
-    static const bool allowOUStringConcat = false;
-    };
+    char* operator()( char* buffer, const OStringLiteral<N>& str ) const { 
return addDataHelper( buffer, str.getStr(), str.getLength() ); }
+};
 
 /**
  @internal
diff --git a/include/rtl/stringconcat.hxx b/include/rtl/stringconcat.hxx
index c2862c5c49ad..24dabe15c0bb 100644
--- a/include/rtl/stringconcat.hxx
+++ b/include/rtl/stringconcat.hxx
@@ -60,283 +60,220 @@ Helper class for converting a given type to a string 
representation.
 */
 template< typename T >
 struct ToStringHelper
-    {
+{
     /// Return length of the string representation of the given object.
-    static std::size_t length( const T& );
+    // static std::size_t length( const T& );
     /// Add 8-bit representation of the given object to the given buffer and 
return position right after the added data.
-    static char* addData( char* buffer, const T& ) SAL_RETURNS_NONNULL;
+    // char* operator()( char* buffer, const T& ) const SAL_RETURNS_NONNULL;
     /// Add Unicode representation of the given object to the given buffer and 
return position right after the added data.
-    static sal_Unicode* addData( sal_Unicode* buffer, const T& ) 
SAL_RETURNS_NONNULL;
-    /// If true, T can be used in concatenation resulting in OString.
-    static const bool allowOStringConcat = false;
-    /// If true, T can be used in concatenation resulting in OUString.
-    static const bool allowOUStringConcat = false;
-    };
+    // sal_Unicode* operator()( sal_Unicode* buffer, const T& ) const 
SAL_RETURNS_NONNULL;
+};
 
-inline
-char* addDataHelper( char* buffer, const char* data, std::size_t length )
-    {
-    if (length != 0) {
-        memcpy( buffer, data, length );
-    }
-    return buffer + length;
-    }
+/// If true, T can be used in concatenation resulting in O(U)String.
+template<typename C, typename T, class Enable = void> constexpr bool 
allowStringConcat = false;
+template<typename C, typename T> constexpr bool allowStringConcat<C, T, 
std::enable_if_t<std::is_invocable_v<ToStringHelper<T>, C*, T>>> = true;
 
-inline
-sal_Unicode* addDataHelper( sal_Unicode* buffer, const sal_Unicode* data, 
std::size_t length )
-    {
+template <typename C> inline
+C* addDataHelper( C* buffer, const C* data, std::size_t length )
+{
     if (length != 0) {
-        memcpy( buffer, data, length * sizeof( sal_Unicode ));
+        memcpy( buffer, data, length * sizeof( C ));
     }
     return buffer + length;
-    }
+}
 
 inline
 sal_Unicode* addDataLiteral( sal_Unicode* buffer, const char* data, 
std::size_t length )
-    {
+{
     for( std::size_t i = 0; i != length; ++i )
         *buffer++ = *data++;
     return buffer;
-    }
-
-inline
-char* addDataCString( char* buffer, const char* str )
-    {
-    while( *str != '\0' )
-        *buffer++ = *str++;
-    return buffer;
-    }
+}
 
-inline
-sal_Unicode* addDataUString( sal_Unicode* buffer, const sal_Unicode* str )
-    {
+template <typename C> inline
+C* addDataString( C* buffer, const C* str )
+{
     while( *str != '\0' )
         *buffer++ = *str++;
     return buffer;
-    }
+}
 
 template<>
 struct ToStringHelper< const char* >
-    {
+{
     static std::size_t length( const char* str ) {
         return str ? strlen( str ) : 0;
     }
-    static char* addData( char* buffer, const char* str ) {
-        return str ? addDataCString( buffer, str ) : buffer;
+    char* operator()( char* buffer, const char* str ) const {
+        return str ? addDataString( buffer, str ) : buffer;
     }
-    static const bool allowOStringConcat = true;
-    static const bool allowOUStringConcat = false;
-    };
+};
 
 template<>
 struct ToStringHelper< char* > : public ToStringHelper< const char* > {};
 
 template< std::size_t N >
 struct ToStringHelper< char[ N ] >
-    {
+{
     static std::size_t length( const char str[ N ] ) {
         return strlen( str );
     }
-    static char* addData( char* buffer, const char str[ N ] ) { return 
addDataCString( buffer, str ); }
-    static const bool allowOStringConcat = true;
-    static const bool allowOUStringConcat = false;
-    };
+    char* operator()( char* buffer, const char str[ N ] ) const { return 
addDataString( buffer, str ); }
+};
 
 template< std::size_t N >
 struct ToStringHelper< const char[ N ] >
-    {
+{
     static std::size_t length( const char str[ N ] ) { (void)str; assert( 
strlen( str ) == N - 1 ); return N - 1; }
-    static char* addData( char* buffer, const char str[ N ] ) { return 
addDataHelper( buffer, str, N - 1 ); }
-    static sal_Unicode* addData( sal_Unicode* buffer, const char str[ N ] ) { 
return addDataLiteral( buffer, str, N - 1 ); }
-    static const bool allowOStringConcat = true;
-    static const bool allowOUStringConcat = true;
-    };
+    char* operator()( char* buffer, const char str[ N ] ) const { return 
addDataHelper( buffer, str, N - 1 ); }
+    sal_Unicode* operator()( sal_Unicode* buffer, const char str[ N ] ) const 
{ return addDataLiteral( buffer, str, N - 1 ); }
+};
 
 template<>
 struct ToStringHelper<OStringChar>
-    {
+{
     static std::size_t length(OStringChar) { return 1; }
-    static char* addData(char* buffer, OStringChar data)
+    char* operator()(char* buffer, OStringChar data) const
     { return addDataHelper(buffer, &data.c, 1); }
-    static bool const allowOStringConcat = true;
-    static bool const allowOUStringConcat = false;
-    };
+};
 
 template<>
 struct ToStringHelper< const sal_Unicode* >
-    {
+{
     static std::size_t length( const sal_Unicode* str ) {
         return str ? std::char_traits<char16_t>::length( str ) : 0;
     }
-    static sal_Unicode* addData( sal_Unicode* buffer, const sal_Unicode* str ) 
{
-        return str ? addDataUString( buffer, str ) : buffer;
+    sal_Unicode* operator()( sal_Unicode* buffer, const sal_Unicode* str ) 
const {
+        return str ? addDataString( buffer, str ) : buffer;
     }
-    static const bool allowOStringConcat = false;
-    static const bool allowOUStringConcat = true;
-    };
+};
 
 template<>
 struct ToStringHelper< sal_Unicode* > : public ToStringHelper< const 
sal_Unicode* > {};
 
 template<std::size_t N>
 struct ToStringHelper<sal_Unicode[ N ]>
-    {
+{
     static std::size_t length( const sal_Unicode str[ N ] ) {
         return std::char_traits<char16_t>::length( str );
     }
-    static sal_Unicode * addData(sal_Unicode * buffer, sal_Unicode const 
str[N])
+    sal_Unicode * operator()(sal_Unicode * buffer, sal_Unicode const str[N]) 
const
     { return addDataHelper(buffer, str, N - 1); }
-    static bool const allowOStringConcat = false;
-    static bool const allowOUStringConcat = true;
-    };
+};
 
 template<std::size_t N>
 struct ToStringHelper<sal_Unicode const[N]>
-    {
+{
     static std::size_t length( const sal_Unicode str[ N ] ) { (void)str; 
assert( std::char_traits<char16_t>::length( str ) == N - 1 ); return N - 1; }
-    static sal_Unicode * addData(sal_Unicode * buffer, sal_Unicode const 
str[N])
+    sal_Unicode * operator()(sal_Unicode * buffer, sal_Unicode const str[N]) 
const
     { return addDataHelper(buffer, str, N - 1); }
-    static bool const allowOStringConcat = false;
-    static bool const allowOUStringConcat = true;
-    };
+};
 
 template<>
 struct ToStringHelper<OUStringChar_>
-    {
+{
     static std::size_t length(OUStringChar_) { return 1; }
-    static sal_Unicode * addData(sal_Unicode * buffer, OUStringChar_ literal)
+    sal_Unicode * operator()(sal_Unicode * buffer, OUStringChar_ literal) const
     { return addDataHelper(buffer, &literal.c, 1); }
-    static bool const allowOStringConcat = false;
-    static bool const allowOUStringConcat = true;
-    };
-
-/**
-@internal
-
-Objects returned by operator+, instead of OString. These objects (possibly 
recursively) keep a representation of the whole
-concatenation operation.
-
-If you get a build error related to this class, you most probably need to 
explicitly convert the result of a string
-concatenation to OString.
-*/
-template< typename T1, typename T2 >
-struct OStringConcat
-    {
-    public:
-        OStringConcat( const T1& left_, const T2& right_ ) : left( left_ ), 
right( right_ ) {}
-        std::size_t length() const { return ToStringHelper< T1 >::length( left 
) + ToStringHelper< T2 >::length( right ); }
-        char* addData( char* buffer ) const SAL_RETURNS_NONNULL { return 
ToStringHelper< T2 >::addData( ToStringHelper< T1 >::addData( buffer, left ), 
right ); }
-        // NOTE here could be functions that would forward to the "real" 
temporary OString. Note however that e.g. getStr()
-        // is not so simple, as the OString temporary must live long enough 
(i.e. can't be created here in a function, a wrapper
-        // temporary object containing it must be returned instead).
-    private:
-        const T1& left;
-        const T2& right;
-    };
+};
 
 /**
 @internal
 
-Objects returned by operator+, instead of OUString. These objects (possibly 
recursively) keep a representation of the whole
+Objects returned by operator+, instead of O(U)String. These objects (possibly 
recursively) keep a representation of the whole
 concatenation operation.
 
 If you get a build error related to this class, you most probably need to 
explicitly convert the result of a string
-concatenation to OUString.
+concatenation to O(U)String.
 */
-template< typename T1, typename T2 >
-struct OUStringConcat
-    {
-    public:
-        OUStringConcat( const T1& left_, const T2& right_ ) : left( left_ ), 
right( right_ ) {}
-        std::size_t length() const { return ToStringHelper< T1 >::length( left 
) + ToStringHelper< T2 >::length( right ); }
-        sal_Unicode* addData( sal_Unicode* buffer ) const SAL_RETURNS_NONNULL 
{ return ToStringHelper< T2 >::addData( ToStringHelper< T1 >::addData( buffer, 
left ), right ); }
-    private:
-        const T1& left;
-        const T2& right;
-    };
+template <typename C, typename T1, typename T2, 
std::enable_if_t<allowStringConcat<C, T1> && allowStringConcat<C, T2>, int> = 0 
>
+struct StringConcat
+{
+public:
+    StringConcat( const T1& left_, const T2& right_ ) : left( left_ ), right( 
right_ ) {}
+    std::size_t length() const { return ToStringHelper< T1 >::length( left ) + 
ToStringHelper< T2 >::length( right ); }
+    C* addData( C* buffer ) const SAL_RETURNS_NONNULL { return ToStringHelper< 
T2 >()( ToStringHelper< T1 >()( buffer, left ), right ); }
+    // NOTE here could be functions that would forward to the "real" temporary 
O(U)String. Note however that e.g. getStr()
+    // is not so simple, as the O(U)String temporary must live long enough 
(i.e. can't be created here in a function, a wrapper
+    // temporary object containing it must be returned instead).
+private:
+    const T1& left;
+    const T2& right;
+};
 
-template< typename T1, typename T2 >
-struct ToStringHelper< OStringConcat< T1, T2 > >
-    {
-    static std::size_t length( const OStringConcat< T1, T2 >& c ) { return 
c.length(); }
-    static char* addData( char* buffer, const OStringConcat< T1, T2 >& c ) 
SAL_RETURNS_NONNULL { return c.addData( buffer ); }
-    static const bool allowOStringConcat = ToStringHelper< T1 
>::allowOStringConcat && ToStringHelper< T2 >::allowOStringConcat;
-    static const bool allowOUStringConcat = false;
-    };
+template <typename C, typename T1, typename T2> struct 
ToStringHelper<StringConcat<C, T1, T2>>
+{
+    static std::size_t length(const StringConcat<C, T1, T2 >& c) { return 
c.length(); }
+    C* operator()(C* buffer, const StringConcat<C, T1, T2>& c) const 
SAL_RETURNS_NONNULL { return c.addData(buffer); }
+};
 
-template< typename T1, typename T2 >
-struct ToStringHelper< OUStringConcat< T1, T2 > >
-    {
-    static std::size_t length( const OUStringConcat< T1, T2 >& c ) { return 
c.length(); }
-    static sal_Unicode* addData( sal_Unicode* buffer, const OUStringConcat< 
T1, T2 >& c ) SAL_RETURNS_NONNULL { return c.addData( buffer ); }
-    static const bool allowOStringConcat = false;
-    static const bool allowOUStringConcat = ToStringHelper< T1 
>::allowOUStringConcat && ToStringHelper< T2 >::allowOUStringConcat;
-    };
+template <typename T1, typename T2> using OStringConcat = StringConcat<char, 
T1, T2>;
+template <typename T1, typename T2> using OUStringConcat = 
StringConcat<sal_Unicode, T1, T2>;
 
 template< typename T1, typename T2 >
 [[nodiscard]]
 inline
-typename std::enable_if_t< ToStringHelper< T1 >::allowOStringConcat && 
ToStringHelper< T2 >::allowOStringConcat, OStringConcat< T1, T2 > > operator+( 
const T1& left, const T2& right )
-    {
+OStringConcat< T1, T2 > operator+( const T1& left, const T2& right )
+{
     return OStringConcat< T1, T2 >( left, right );
-    }
+}
 
 // char[N] and const char[N] need to be done explicitly, otherwise the 
compiler likes to treat them the same way for some reason
 template< typename T, std::size_t N >
 [[nodiscard]]
 inline
-typename std::enable_if_t< ToStringHelper< T >::allowOStringConcat, 
OStringConcat< T, const char[ N ] > > operator+( const T& left, const char 
(&right)[ N ] )
-    {
+OStringConcat< T, const char[ N ] > operator+( const T& left, const char 
(&right)[ N ] )
+{
     return OStringConcat< T, const char[ N ] >( left, right );
-    }
+}
 
 template< typename T, std::size_t N >
 [[nodiscard]]
 inline
-typename std::enable_if_t< ToStringHelper< T >::allowOStringConcat, 
OStringConcat< const char[ N ], T > > operator+( const char (&left)[ N ], const 
T& right )
-    {
+OStringConcat< const char[ N ], T > operator+( const char (&left)[ N ], const 
T& right )
+{
     return OStringConcat< const char[ N ], T >( left, right );
-    }
+}
 
 template< typename T, std::size_t N >
 [[nodiscard]]
 inline
-typename std::enable_if_t< ToStringHelper< T >::allowOStringConcat, 
OStringConcat< T, char[ N ] > > operator+( const T& left, char (&right)[ N ] )
-    {
+OStringConcat< T, char[ N ] > operator+( const T& left, char (&right)[ N ] )
+{
     return OStringConcat< T, char[ N ] >( left, right );
-    }
+}
 
 template< typename T, std::size_t N >
 [[nodiscard]]
 inline
-typename std::enable_if_t< ToStringHelper< T >::allowOStringConcat, 
OStringConcat< char[ N ], T > > operator+( char (&left)[ N ], const T& right )
-    {
+OStringConcat< char[ N ], T > operator+( char (&left)[ N ], const T& right )
+{
     return OStringConcat< char[ N ], T >( left, right );
-    }
+}
 
 template< typename T1, typename T2 >
 [[nodiscard]]
 inline
-typename std::enable_if_t< ToStringHelper< T1 >::allowOUStringConcat && 
ToStringHelper< T2 >::allowOUStringConcat, OUStringConcat< T1, T2 > > 
operator+( const T1& left, const T2& right )
-    {
+OUStringConcat< T1, T2 > operator+( const T1& left, const T2& right )
+{
     return OUStringConcat< T1, T2 >( left, right );
-    }
+}
 
 template< typename T1, typename T2 >
 [[nodiscard]]
 inline
-typename std::enable_if_t< ToStringHelper< T1 >::allowOUStringConcat && 
ToStringHelper< T2 >::allowOUStringConcat && 
libreoffice_internal::ConstCharArrayDetector< T1, void >::ok, OUStringConcat< 
T1, T2 > > operator+( T1& left, const T2& right )
-    {
+typename std::enable_if_t< libreoffice_internal::ConstCharArrayDetector< T1, 
void >::ok, OUStringConcat< T1, T2 > > operator+( T1& left, const T2& right )
+{
     return OUStringConcat< T1, T2 >( left, right );
-    }
+}
 
 template< typename T1, typename T2 >
 [[nodiscard]]
 inline
-typename std::enable_if_t< ToStringHelper< T1 >::allowOUStringConcat && 
ToStringHelper< T2 >::allowOUStringConcat && 
libreoffice_internal::ConstCharArrayDetector< T2, void >::ok, OUStringConcat< 
T1, T2 > > operator+( const T1& left, T2& right )
-    {
+typename std::enable_if_t< libreoffice_internal::ConstCharArrayDetector< T2, 
void >::ok, OUStringConcat< T1, T2 > > operator+( const T1& left, T2& right )
+{
     return OUStringConcat< T1, T2 >( left, right );
-    }
+}
 
 #ifdef RTL_STRING_UNITTEST_CONCAT
 // Special overload to catch the remaining invalid combinations. The helper 
struct must
@@ -385,6 +322,31 @@ template <typename T1, typename T2> auto 
Concat2View(OUStringConcat<T1, T2> cons
     return StringConcatenation<char16_t>(c);
 }
 
+/**
+* O(U)StringNumber implementation
+*/
+
+template <typename C, typename Number, std::size_t nBufSize> struct 
StringNumberBase
+{
+    using number_t = Number;
+    using base_t = StringNumberBase;
+    // O(U)String::number(value).getStr() is very common (writing xml code, 
...),
+    // so implement that one also here, to avoid having to explicitly convert
+    // to O(U)String in all such places
+    const C* getStr() const SAL_RETURNS_NONNULL { return buf; }
+    StringNumberBase&& toAsciiUpperCase()
+    {
+        if constexpr (sizeof(C) == sizeof(char))
+            rtl_str_toAsciiUpperCase_WithLength(buf, length);
+        else
+            rtl_ustr_toAsciiUpperCase_WithLength(buf, length);
+        return std::move(*this);
+    }
+    operator std::basic_string_view<C>() const { return 
std::basic_string_view<C>(buf, length); }
+    C buf[nBufSize];
+    sal_Int32 length;
+};
+
 /**
  @internal
 
@@ -396,68 +358,41 @@ OString::number() to OString.
 template< typename T >
 struct OStringNumber;
 
-template <typename Number, std::size_t nBufSize> struct OStringNumberBase
-{
-    using number_t = Number;
-    // OString::number(value).getStr() is very common (writing xml code, ...),
-    // so implement that one also here, to avoid having to explicitly to 
convert
-    // to OString in all such places
-    const char * getStr() const SAL_RETURNS_NONNULL { return buf; }
-    OStringNumber<number_t>&& toAsciiUpperCase()
-    {
-        rtl_str_toAsciiUpperCase_WithLength(buf, length);
-        return std::move(*static_cast<OStringNumber<number_t>*>(this));
-    }
-    operator std::string_view() const { return std::string_view(buf, length); }
-    char buf[nBufSize];
-    sal_Int32 length;
-};
-
 template<>
 struct OStringNumber< int >
-    : public OStringNumberBase<int, RTL_STR_MAX_VALUEOFINT32>
+    : public StringNumberBase<char, int, RTL_STR_MAX_VALUEOFINT32>
 {
     OStringNumber(number_t i, sal_Int16 radix) { length = 
rtl_str_valueOfInt32(buf, i, radix); }
 };
 
 template<>
 struct OStringNumber< long long >
-    : public OStringNumberBase<long long, RTL_STR_MAX_VALUEOFINT64>
+    : public StringNumberBase<char, long long, RTL_STR_MAX_VALUEOFINT64>
 {
     OStringNumber(number_t i, sal_Int16 radix) { length = 
rtl_str_valueOfInt64(buf, i, radix); }
 };
 
 template<>
 struct OStringNumber< unsigned long long >
-    : public OStringNumberBase<unsigned long long, RTL_STR_MAX_VALUEOFUINT64>
+    : public StringNumberBase<char, unsigned long long, 
RTL_STR_MAX_VALUEOFUINT64>
 {
     OStringNumber(number_t i, sal_Int16 radix) { length = 
rtl_str_valueOfUInt64(buf, i, radix); }
 };
 
 template<>
 struct OStringNumber< float >
-    : public OStringNumberBase<float, RTL_STR_MAX_VALUEOFFLOAT>
+    : public StringNumberBase<char, float, RTL_STR_MAX_VALUEOFFLOAT>
 {
     OStringNumber(number_t f) { length = rtl_str_valueOfFloat(buf, f); }
 };
 
 template<>
 struct OStringNumber< double >
-    : public OStringNumberBase<double, RTL_STR_MAX_VALUEOFDOUBLE>
+    : public StringNumberBase<char, double, RTL_STR_MAX_VALUEOFDOUBLE>
 {
     OStringNumber(number_t d) { length = rtl_str_valueOfDouble(buf, d); }
 };
 
-template< typename T >
-struct ToStringHelper< OStringNumber< T > >
-    {
-    static std::size_t length( const OStringNumber< T >& n ) { return 
n.length; }
-    static char* addData( char* buffer, const OStringNumber< T >& n ) 
SAL_RETURNS_NONNULL { return addDataHelper( buffer, n.buf, n.length ); }
-    static const bool allowOStringConcat = true;
-    static const bool allowOUStringConcat = false;
-    };
-
-
 /**
  @internal
 
@@ -469,109 +404,70 @@ OUString::number() to OUString.
 template< typename T >
 struct OUStringNumber;
 
-template <typename Number, std::size_t nBufSize> struct OUStringNumberBase
-{
-    using number_t = Number;
-    OUStringNumber<number_t>&& toAsciiUpperCase()
-    {
-        rtl_ustr_toAsciiUpperCase_WithLength(buf, length);
-        return std::move(*static_cast<OUStringNumber<number_t>*>(this));
-    }
-    operator std::u16string_view() const { return std::u16string_view(buf, 
length); }
-    sal_Unicode buf[nBufSize];
-    sal_Int32 length;
-};
-
 template<>
 struct OUStringNumber< int >
-    : public OUStringNumberBase<int, RTL_USTR_MAX_VALUEOFINT32>
+    : public StringNumberBase<sal_Unicode, int, RTL_USTR_MAX_VALUEOFINT32>
 {
     OUStringNumber(number_t i, sal_Int16 radix) { length = 
rtl_ustr_valueOfInt32(buf, i, radix); }
 };
 
 template<>
 struct OUStringNumber< long long >
-    : public OUStringNumberBase<long long, RTL_USTR_MAX_VALUEOFINT64>
+    : public StringNumberBase<sal_Unicode, long long, 
RTL_USTR_MAX_VALUEOFINT64>
 {
     OUStringNumber(number_t i, sal_Int16 radix) { length = 
rtl_ustr_valueOfInt64(buf, i, radix); }
 };
 
 template<>
 struct OUStringNumber< unsigned long long >
-    : public OUStringNumberBase<unsigned long long, RTL_USTR_MAX_VALUEOFUINT64>
+    : public StringNumberBase<sal_Unicode, unsigned long long, 
RTL_USTR_MAX_VALUEOFUINT64>
 {
     OUStringNumber(number_t i, sal_Int16 radix) { length = 
rtl_ustr_valueOfUInt64(buf, i, radix); }
 };
 
 template<>
 struct OUStringNumber< float >
-    : public OUStringNumberBase<float, RTL_USTR_MAX_VALUEOFFLOAT>
+    : public StringNumberBase<sal_Unicode, float, RTL_USTR_MAX_VALUEOFFLOAT>
 {
     OUStringNumber(number_t f) { length = rtl_ustr_valueOfFloat(buf, f); }
 };
 
 template<>
 struct OUStringNumber< double >
-    : public OUStringNumberBase<double, RTL_USTR_MAX_VALUEOFDOUBLE>
+    : public StringNumberBase<sal_Unicode, double, RTL_USTR_MAX_VALUEOFDOUBLE>
 {
     OUStringNumber(number_t d) { length = rtl_ustr_valueOfDouble(buf, d); }
 };
 
-template< typename T >
-struct ToStringHelper< OUStringNumber< T > >
-    {
-    static std::size_t length( const OUStringNumber< T >& n ) { return 
n.length; }
-    static sal_Unicode* addData( sal_Unicode* buffer, const OUStringNumber< T 
>& n ) SAL_RETURNS_NONNULL { return addDataHelper( buffer, n.buf, n.length ); }
-    static const bool allowOStringConcat = false;
-    static const bool allowOUStringConcat = true;
-    };
-
-template<> struct ToStringHelper<std::string_view> {
-    static constexpr std::size_t length(std::string_view s) { return s.size(); 
}
-
-    static char * addData(char * buffer, std::string_view s) 
SAL_RETURNS_NONNULL
-    { return addDataHelper(buffer, s.data(), s.size()); }
-
-    static constexpr bool allowOStringConcat = true;
-    static constexpr bool allowOUStringConcat = false;
+template< typename C, typename T, std::size_t nBufSize >
+struct ToStringHelper< StringNumberBase< C, T, nBufSize > >
+{
+    static std::size_t length( const StringNumberBase< C, T, nBufSize >& n ) { 
return n.length; }
+    C* operator()( C* buffer, const StringNumberBase< C, T, nBufSize >& n ) 
const SAL_RETURNS_NONNULL { return addDataHelper( buffer, n.buf, n.length ); }
 };
 
-template<> struct ToStringHelper<std::u16string_view> {
-    static constexpr std::size_t length(std::u16string_view s) { return 
s.size(); }
+template<typename T> struct ToStringHelper<OStringNumber<T>> : public 
ToStringHelper<typename OStringNumber<T>::base_t> {};
+template<typename T> struct ToStringHelper<OUStringNumber<T>> : public 
ToStringHelper<typename OUStringNumber<T>::base_t> {};
 
-    static sal_Unicode * addData(sal_Unicode * buffer, std::u16string_view s) 
SAL_RETURNS_NONNULL
-    { return addDataHelper(buffer, s.data(), s.size()); }
+template<typename C> struct ToStringHelper<std::basic_string_view<C>> {
+    static constexpr std::size_t length(std::basic_string_view<C> s) { return 
s.size(); }
 
-    static constexpr bool allowOStringConcat = false;
-    static constexpr bool allowOUStringConcat = true;
+    C * operator()(C * buffer, std::basic_string_view<C> s) const 
SAL_RETURNS_NONNULL
+    { return addDataHelper(buffer, s.data(), s.size()); }
 };
 
-// An internal marker class used by OString::Concat:
-struct OStringConcatMarker {};
+// An internal marker class used by O(U)String::Concat:
+template<typename C> struct StringConcatMarker {};
 
-template<> struct ToStringHelper<OStringConcatMarker> {
-    static constexpr std::size_t length(OStringConcatMarker) { return 0; }
+template<typename C> struct ToStringHelper<StringConcatMarker<C>> {
+    static constexpr std::size_t length(StringConcatMarker<C>) { return 0; }
 
-    static constexpr char * addData(char * buffer, OStringConcatMarker) 
SAL_RETURNS_NONNULL
+    constexpr C * operator()(C * buffer, StringConcatMarker<C>) const 
SAL_RETURNS_NONNULL
     { return buffer; }
-
-    static constexpr bool allowOStringConcat = true;
-    static constexpr bool allowOUStringConcat = false;
 };
 
-// An internal marker class used by OUString::Concat:
-struct OUStringConcatMarker {};
-
-template<> struct ToStringHelper<OUStringConcatMarker> {
-    static constexpr std::size_t length(OUStringConcatMarker) { return 0; }
-
-    static constexpr sal_Unicode * addData(sal_Unicode * buffer, 
OUStringConcatMarker)
-        SAL_RETURNS_NONNULL
-    { return buffer; }
-
-    static constexpr bool allowOStringConcat = false;
-    static constexpr bool allowOUStringConcat = true;
-};
+using OStringConcatMarker = StringConcatMarker<char>;
+using OUStringConcatMarker = StringConcatMarker<sal_Unicode>;
 
 } // namespace
 
diff --git a/include/rtl/ustrbuf.hxx b/include/rtl/ustrbuf.hxx
index c5d6b2e9ee1b..af7d0d0d9ef6 100644
--- a/include/rtl/ustrbuf.hxx
+++ b/include/rtl/ustrbuf.hxx
@@ -242,8 +242,8 @@ public:
      @overload
      @internal
     */
-    template< typename T >
-    OUStringBuffer( OUStringNumber< T >&& n )
+    template< typename T, std::size_t N >
+    OUStringBuffer( StringNumberBase< sal_Unicode, T, N >&& n )
         : pData(NULL)
         , nCapacity( n.length + 16 )
     {
@@ -380,8 +380,8 @@ public:
     }
 
     /** @overload @internal */
-    template<typename T>
-    OUStringBuffer & operator =(OUStringNumber<T> && n)
+    template<typename T, std::size_t N>
+    OUStringBuffer & operator =(StringNumberBase<sal_Unicode, T, N> && n)
     {
         *this = OUStringBuffer( std::move( n ) );
         return *this;
@@ -722,8 +722,8 @@ public:
      @overload
      @internal
     */
-    template< typename T >
-    OUStringBuffer& append( OUStringNumber< T >&& c )
+    template< typename T, std::size_t N >
+    OUStringBuffer& append( StringNumberBase< sal_Unicode, T, N >&& c )
     {
         return append( c.buf, c.length );
     }
@@ -1767,11 +1767,8 @@ private:
 template<> struct ToStringHelper<OUStringBuffer> {
     static std::size_t length(OUStringBuffer const & s) { return 
s.getLength(); }
 
-    static sal_Unicode * addData(sal_Unicode * buffer, OUStringBuffer const & 
s) SAL_RETURNS_NONNULL
+    sal_Unicode * operator()(sal_Unicode * buffer, OUStringBuffer const & s) 
const SAL_RETURNS_NONNULL
     { return addDataHelper(buffer, s.getStr(), s.getLength()); }
-
-    static constexpr bool allowOStringConcat = false;
-    static constexpr bool allowOUStringConcat = true;
 };
 #endif
 
diff --git a/include/rtl/ustring.hxx b/include/rtl/ustring.hxx
index cddba5dfadd5..69575289f6f5 100644
--- a/include/rtl/ustring.hxx
+++ b/include/rtl/ustring.hxx
@@ -502,8 +502,8 @@ public:
      @overload
      @internal
     */
-    template< typename T >
-    OUString( OUStringNumber< T >&& n )
+    template< typename T, std::size_t N >
+    OUString( StringNumberBase< sal_Unicode, T, N >&& n )
         : OUString( n.buf, n.length )
     {}
 #endif
@@ -638,8 +638,8 @@ public:
     }
     template<std::size_t N> OUString & operator =(OUStringLiteral<N> &&) = 
delete;
 
-    template<typename T>
-    OUString & operator =(OUStringNumber<T> && n) {
+    template <typename T, std::size_t N>
+    OUString & operator =(StringNumberBase<sal_Unicode, T, N> && n) {
         // n.length should never be zero, so no need to add an optimization 
for that case
         rtl_uString_newFromStr_WithLength(&pData, n.buf, n.length);
         return *this;
@@ -770,8 +770,8 @@ public:
      @overload
      @internal
     */
-    template< typename T >
-    OUString& operator+=( OUStringNumber< T >&& n ) & {
+    template< typename T, std::size_t N >
+    OUString& operator+=( StringNumberBase< sal_Unicode, T, N >&& n ) & {
         sal_Int32 l = n.length;
         if( l == 0 )
             return *this;
@@ -782,8 +782,8 @@ public:
         pData->length = l;
         return *this;
     }
-    template<typename T> void operator +=(
-        OUStringNumber<T> &&) && = delete;
+    template<typename T, std::size_t N> void operator +=(
+        StringNumberBase<sal_Unicode, T, N> &&) && = delete;
 #endif
 
     /**
@@ -3301,16 +3301,14 @@ public:
     //
     // would not compile):
     template<typename T> [[nodiscard]] static
-    typename std::enable_if_t<
-        ToStringHelper<T>::allowOUStringConcat, 
OUStringConcat<OUStringConcatMarker, T>>
+    OUStringConcat<OUStringConcatMarker, T>
     Concat(T const & value) { return OUStringConcat<OUStringConcatMarker, 
T>({}, value); }
 
     // This overload is needed so that an argument of type 'char const[N]' 
ends up as
     // 'OUStringConcat<rtl::OUStringConcatMarker, char const[N]>' rather than 
as
     // 'OUStringConcat<rtl::OUStringConcatMarker, char[N]>':
     template<typename T, std::size_t N> [[nodiscard]] static
-    typename std::enable_if_t<
-        ToStringHelper<T[N]>::allowOUStringConcat, 
OUStringConcat<OUStringConcatMarker, T[N]>>
+    OUStringConcat<OUStringConcatMarker, T[N]>
     Concat(T (& value)[N]) { return OUStringConcat<OUStringConcatMarker, 
T[N]>({}, value); }
 #endif
 
@@ -3365,24 +3363,20 @@ inline bool operator !=(StringConcatenation<char16_t> 
const & lhs, OUString cons
 */
 template<>
 struct ToStringHelper< OUString >
-    {
+{
     static std::size_t length( const OUString& s ) { return s.getLength(); }
-    static sal_Unicode* addData( sal_Unicode* buffer, const OUString& s ) { 
return addDataHelper( buffer, s.getStr(), s.getLength()); }
-    static const bool allowOStringConcat = false;
-    static const bool allowOUStringConcat = true;
-    };
+    sal_Unicode* operator() ( sal_Unicode* buffer, const OUString& s ) const { 
return addDataHelper( buffer, s.getStr(), s.getLength()); }
+};
 
 /**
  @internal
 */
 template<std::size_t N>
 struct ToStringHelper< OUStringLiteral<N> >
-    {
+{
     static std::size_t length( const OUStringLiteral<N>& str ) { return 
str.getLength(); }
-    static sal_Unicode* addData( sal_Unicode* buffer, const 
OUStringLiteral<N>& str ) { return addDataHelper( buffer, str.getStr(), 
str.getLength() ); }
-    static const bool allowOStringConcat = false;
-    static const bool allowOUStringConcat = true;
-    };
+    sal_Unicode* operator()( sal_Unicode* buffer, const OUStringLiteral<N>& 
str ) const { return addDataHelper( buffer, str.getStr(), str.getLength() ); }
+};
 
 /**
  @internal

Reply via email to