lmi
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [lmi] Dealing with deleted operator<<() overloads for wide char type


From: Greg Chicares
Subject: Re: [lmi] Dealing with deleted operator<<() overloads for wide char types in C++20
Date: Mon, 1 Mar 2021 21:59:59 +0000
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.4.0

On 2/26/21 12:29 AM, Vadim Zeitlin wrote:
> On Thu, 25 Feb 2021 22:35:34 +0000 Greg Chicares <gchicares@sbcglobal.net> 
> wrote:
> 
> GC> On 2/25/21 8:55 PM, Vadim Zeitlin wrote:
> GC> [...]
> GC> > [in C++20] we can't insert
> GC> > a char16_t value into the stream any more.
> GC> > 
> GC> >  There are several ways to solve this, but I wonder if it's even worth
> GC> > solving it at all, or if we could simply remove test_same() calls for 
> the
> GC> > char{16,32}_t and wchar_t types in the test? It seems exceedingly 
> unlikely
> GC> > that bourn_cast() would be used with any of these types and, in fact, I
> GC> > wonder if we shouldn't just prevent it from being used with them.
> GC> 
> GC> I'd like bourn_cast to work in every case where it could possibly make
> GC> any sense--not excluding cases that are valid but seem unlikely--and
> GC> likewise for its unit test.
> 
>  This is perfectly understandable, but IMO casting chars is exactly a case
> which just doesn't make sense. You wouldn't, presumably, attempt to make
> bourn_cast() work with strings, so why would you ever want to use it with
> char{16,32}_t which can be exactly the same thing as UTF-8-encoded
> multi-byte string?

I'm not sure I follow. As you know, C++20 (N4861) says [6.8.1]:

| 11. Types bool, char, wchar_t, char8_t, char16_t, char32_t, and
| the signed and unsigned integer types are collectively called
| integral types. A synonym for integral type is integer type.

| 12. There are three floating-point types: float, double, and
| long double. ... Integral and floating-point types are
| collectively called arithmetic types.

Shouldn't the domain of bourn_cast<T,U> be all arithmetic types {T,U}?

I don't even know what these goofy types are supposed to be: maybe
UCS-2 and UCS-4, or something like that. But I don't see why the
motivation for their existence would need to be considered here:
they're arithmetic types, and isn't that all I need to know?

> GC> I'd be inclined to replace
> GC>   INVOKE_BOOST_TEST_EQUAL(x, y, file, line);
> GC> (only where it is actually problematic) with
> GC>   INVOKE_BOOST_TEST(x == y, file, line);
> GC> (I haven't tested that, but I'm sure something like it would work.
> GC> The -"_EQUAL" macros are handy because on failure they print the two
> GC> values that are unexpectedly unequal; but that handiness isn't very
> GC> important for debugged code.)
> GC> 
> GC> Do you see a better way, or should I just make it so?
> 
>  I indeed think this would work, but doing it just for these types would be
> a bit messy because we use it in a template function, so it'd require an
> "if constexpr" (which is, of course, only a bit messy, compared to
> SFINAE-level mess we'd have to use with pre-C++17 C++).

I did something much simpler in commit e89831e23. IOW, here:

> GC> I'd be inclined to replace
> GC>   INVOKE_BOOST_TEST_EQUAL(x, y, file, line);
> GC> (only where it is actually problematic) with
> GC>   INVOKE_BOOST_TEST(x == y, file, line);

what does the (ambiguous) "actually problematic" mean? I
intended "on any line flagged in a compiler diagnostic,
regardless of what remote line it was invoked from": thus,
"potentially problematic" might have been a better phrase.

The tests for equality are preserved. All that's lost is
the incidental printing of their (unequal) values.

But maybe I misunderstand something. From my POV above,
integral types are integral types, and that's that, so
making some of them streamable and others not is lunacy.

>  It would also still leave us with the same problem in any other place
> where we might use BOOST_TEST_EQUAL[*] with these types.

But AFAICS that no longer occurs anywhere, since e89831e23.

> So I was rather
> thinking of implementing a complete solution for this by defining a
> template lmi_test::to_string() function

Nothing new to invent:

template<typename T>
lmi_test::to_string(T t)
  {return value_cast<std::string>(t);}

Would you be in favor of a change such as the following?

 #define LMI_ASSERT_EQUAL(observed,expected)                         \
     LMI_ASSERT_WITH_MSG                                             \
         ((observed) == (expected)                                   \
-        ,"expected " << (expected) << " vs observed " << (observed) \
+        ,      "expected " << value_cast<std::string>(expected) "\
+        << " vs observed " << value_cast<std::string>(observed) \
         )

I'd be somewhat opposed because that introduces heavyweight
header "value_cast.hpp" into lightweight "assert_lmi.hpp",
compounding the fragility of assertion code that already
uses heavyweight std:: stuff that can throw exceptions.

We would be able to consider using std::to_string(), except
that they defined its domain to include certain integral
types but exclude others.

>  But my preference would still be to just forbid using bourn_cast() with
> the wide char types as I remain convinced that this is an operation which
> simply never makes sense.

Again, maybe I'm missing something, but to me:
 - arithmetic types should be streamable
 - the real error is that types like char16_t and char32_t exist
   
> [*] We really, really ought to rename these macros to LMI_TEST_EQUAL() or
>     something else not starting with BOOST_, pretending that they come from
>     Boost is still confusing, even after all these years, and just imagine
>     how puzzling it is to anybody new to lmi code base (I didn't have to
>     imagine this when I saw Ilya being completely misled by their names
>     relatively recently).

Okay, I'll do that.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]