boostorg / test

The reference C++ unit testing framework (TDD, xUnit, C++03/11/14/17)
http://boost.org/libs/test
Boost Software License 1.0
183 stars 140 forks source link

question: how to correctly create print helpers for '<<' explicitly removed in C++20? #409

Open mbel1 opened 9 months ago

mbel1 commented 9 months ago

Hello! while project description states that this framework is for C++17 max, could anyone possibly help me with C++20 compatibility issue? my problem is that in C++20 operator << for printing wide strings (std::wstring, `const wchar_t*, etc) was explicitly removed. In C++17 I could define helper template like

template<> std::ostream& operator<<(std::ostream& o, const std::wstring& what) { o << convert_to_char(what); return o; }

and it worked perfectly. In C++20 this no longer works, as this operator is explicitly deleted, so this template is not even considered. I found that I can partially solve the issue for std::wstring by defining this specialization

namespace boost {
namespace test_tools {
namespace tt_detail {
namespace impl {
template<> std::ostream& boost_test_print_type_impl::operator()(std::ostream& o, const std::wstring& what) const
{
    o << convert_to_char(what); return o;
}
} // impl
} // tt_detail
} // test_tools
} // boost

but this works only for std::wstring, not for any wide string literals in a test like

BOOST_TEST(someWideString == L"expectations");

as I found no way to match R const& r against wchar_t[12] so I can't create a specialization in similar manner.

what need to be done, so BOOST_TEST could understand wide string literals in C++20?

if you need compiler specifics: this is Xcode 15 on macOS

mbel1 commented 9 months ago

It turned out that I was incorrect in my analysis of the problem: it turned out that old workaround with std::ostream& operator<<(std::ostream& o, const std::wstring& what) works just fine. But with C++20 this workaround no longer works for wide-string literals like L"expectation": when C++ tries to apply td::ostream& operator<<(std::ostream& o, const wchar_t* what) it finds that it is deleted, so conversion to std::wstring is not considered. So obvious fix is to use wstring's, like

using std::string_literals;
BOOST_TEST(someWideString == L"expectations"s);

but is there a way to make BOOST_TEST to work with const wchar_t* ?

zhihaoy commented 7 months ago

So obvious fix is to use wstring's, like

using std::string_literals;
BOOST_TEST(someWideString == L"expectations"s);

but is there a way to make BOOST_TEST to work with const wchar_t* ?

BOOST_TEST does work with const wchar_t* (not necessarily printing the string); it just doesn't work with const wchar_t[N]. BOOST_TEST has special handling for pointers to arrays of characters because pointers might be null. Arrays, on the other hand, rely on the presence of <<.

My current workaround is

BOOST_TEST(someWideString == +L"expectations");