Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

is_stream_insertable_v and reserved identifier fix #616

Merged
merged 1 commit into from
Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions example/expect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@

constexpr auto sum = [](auto... args) { return (0 + ... + args); };

struct dummy_struct{};
int main() {
using namespace boost::ut;


"operators"_test = [] {
expect(0_i == sum());
expect(2_i != sum(1, 2));
Expand All @@ -39,6 +41,23 @@ int main() {
};

"eq/neq/gt/ge/lt/le"_test = [] {
// type_traits::is_stream_insertable_v constraint check

static_assert( type_traits::is_stream_insertable_v<int>);
static_assert( !type_traits::is_stream_insertable_v<dummy_struct>);

// it seems it produces nice error information
// leaving this as easy way to check failing compilation in case of doubt
// expect(eq(dummy_struct{}, sum(40, 2)));
// gcc
// expect.cpp:46:14: error: no matching function for call to ‘eq(dummy_struct, int)’
// 46 | expect(eq(dummy_struct{}, sum(40, 2)));
// | ~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~
// clang
// expect.cpp:51:12: error: no matching function for call to 'eq'
// 51 | expect(eq(dummy_struct{}, sum(40, 2)));
// | ^~

expect(eq(42, sum(40, 2)));
expect(neq(1, 2));
expect(eq(sum(1), 1) and neq(sum(1, 2), 2));
Expand Down
54 changes: 43 additions & 11 deletions include/boost/ut.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export import std;
#include <source_location>
#endif

struct _unique_name_for_auto_detect_prefix_and_suffix_lenght_0123456789_struct {
struct unique_name_for_auto_detect_prefix_and_suffix_lenght_0123456789_struct_ {
};

BOOST_UT_EXPORT
Expand Down Expand Up @@ -298,15 +298,15 @@ template <typename TargetType>

inline constexpr const std::string_view raw_type_name =
get_template_function_name_use_decay_type<
_unique_name_for_auto_detect_prefix_and_suffix_lenght_0123456789_struct>();
unique_name_for_auto_detect_prefix_and_suffix_lenght_0123456789_struct_>();

inline constexpr const std::size_t raw_length = raw_type_name.length();
inline constexpr const std::string_view need_name =
#if defined(_MSC_VER) and not defined(__clang__)
"struct "
"_unique_name_for_auto_detect_prefix_and_suffix_lenght_0123456789_struct";
"unique_name_for_auto_detect_prefix_and_suffix_lenght_0123456789_struct_";
#else
"_unique_name_for_auto_detect_prefix_and_suffix_lenght_0123456789_struct";
"unique_name_for_auto_detect_prefix_and_suffix_lenght_0123456789_struct_";
#endif
inline constexpr const std::size_t need_length = need_name.length();
static_assert(need_length <= raw_length,
Expand Down Expand Up @@ -1325,6 +1325,17 @@ struct aborts_ : op {
namespace type_traits {
template <class T>
inline constexpr auto is_op_v = __is_base_of(detail::op, T);

template <typename T, typename = void>
struct is_stream_insertable : std::false_type {};

template <typename T>
struct is_stream_insertable<
T, std::void_t<decltype(std::declval<std::ostream&>()
<< detail::get(std::declval<T>()))>>
: std::true_type {};
template <typename T>
inline constexpr bool is_stream_insertable_v = is_stream_insertable<T>::value;
} // namespace type_traits

struct colors {
Expand Down Expand Up @@ -3050,32 +3061,53 @@ struct suite {
template <class T = void>
[[maybe_unused]] constexpr auto type = detail::type_<T>();

template <class TLhs, class TRhs>
template <class TLhs, class TRhs,
typename = type_traits::requires_t<
type_traits::is_stream_insertable_v<TLhs> and
type_traits::is_stream_insertable_v<TRhs>>>
[[nodiscard]] constexpr auto eq(const TLhs& lhs, const TRhs& rhs) {
return detail::eq_{lhs, rhs};
}
template <class TLhs, class TRhs, class TEpsilon>
template <class TLhs, class TRhs, class TEpsilon,
typename = type_traits::requires_t<
type_traits::is_stream_insertable_v<TLhs> and
type_traits::is_stream_insertable_v<TRhs>>>
[[nodiscard]] constexpr auto approx(const TLhs& lhs, const TRhs& rhs,
const TEpsilon& epsilon) {
return detail::approx_{lhs, rhs, epsilon};
}
template <class TLhs, class TRhs>
template <class TLhs, class TRhs,
typename = type_traits::requires_t<
type_traits::is_stream_insertable_v<TLhs> and
type_traits::is_stream_insertable_v<TRhs>>>
[[nodiscard]] constexpr auto neq(const TLhs& lhs, const TRhs& rhs) {
return detail::neq_{lhs, rhs};
}
template <class TLhs, class TRhs>
template <class TLhs, class TRhs,
typename = type_traits::requires_t<
type_traits::is_stream_insertable_v<TLhs> and
type_traits::is_stream_insertable_v<TRhs>>>
[[nodiscard]] constexpr auto gt(const TLhs& lhs, const TRhs& rhs) {
return detail::gt_{lhs, rhs};
}
template <class TLhs, class TRhs>
template <class TLhs, class TRhs,
typename = type_traits::requires_t<
type_traits::is_stream_insertable_v<TLhs> and
type_traits::is_stream_insertable_v<TRhs>>>
[[nodiscard]] constexpr auto ge(const TLhs& lhs, const TRhs& rhs) {
return detail::ge_{lhs, rhs};
}
template <class TLhs, class TRhs>
template <class TLhs, class TRhs,
typename = type_traits::requires_t<
type_traits::is_stream_insertable_v<TLhs> and
type_traits::is_stream_insertable_v<TRhs>>>
[[nodiscard]] constexpr auto lt(const TLhs& lhs, const TRhs& rhs) {
return detail::lt_{lhs, rhs};
}
template <class TLhs, class TRhs>
template <class TLhs, class TRhs,
typename = type_traits::requires_t<
type_traits::is_stream_insertable_v<TLhs> and
type_traits::is_stream_insertable_v<TRhs>>>
[[nodiscard]] constexpr auto le(const TLhs& lhs, const TRhs& rhs) {
return detail::le_{lhs, rhs};
}
Expand Down
Loading