Skip to content
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
38 changes: 38 additions & 0 deletions include/iris/type_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,24 @@ struct is_convertible_without_narrowing<From, To>
template<class From, class To>
inline constexpr bool is_convertible_without_narrowing_v = is_convertible_without_narrowing<From, To>::value;

template<class T, class U>
struct is_assignable_without_narrowing : std::false_type
{};

template<class T, class U>
requires
std::is_assignable_v<T, U> &&
(
!std::is_scalar_v<std::remove_reference_t<T>> ||
is_convertible_without_narrowing_v<U, std::remove_reference_t<T>>
)
struct is_assignable_without_narrowing<T, U>
: std::true_type
{};

template<class T, class U>
inline constexpr bool is_assignable_without_narrowing_v = is_assignable_without_narrowing<T, U>::value;

// ----------------------------------------------

namespace detail {
Expand Down Expand Up @@ -552,6 +570,26 @@ struct no_narrowing_resolution<
template<class T, class... Ts>
struct no_narrowing_resolution : detail::no_narrowing_resolution<void, T, Ts...> {};

template<std::size_t I, class T>
struct conversion_overload
{
static std::integral_constant<std::size_t, I> select(T); // not defined
};

template<class... Overloads>
struct conversion_overloads : Overloads...
{
using Overloads::select...;
};

template<class Overloads, class U>
concept conversion_resolves = requires { Overloads::select(std::declval<U>()); };

template<class Overloads, class U, std::size_t I>
concept conversion_selects = requires {
{ Overloads::select(std::declval<U>()) } -> std::same_as<std::integral_constant<std::size_t, I>>;
};

// ----------------------------------------------

namespace detail {
Expand Down
32 changes: 32 additions & 0 deletions test/narrowing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -425,3 +425,35 @@ TEST_CASE("is_assignable_without_any_narrowing", "[type_traits]")

STATIC_CHECK(!iris::is_assignable_without_any_narrowing_v<std::string&, char>); // initializer-list assignment
}

TEST_CASE("is_assignable_without_narrowing", "[type_traits]")
{
STATIC_CHECK(iris::is_assignable_without_narrowing_v<int&, int>);
STATIC_CHECK(iris::is_assignable_without_narrowing_v<long long&, int>);
STATIC_CHECK(!iris::is_assignable_without_narrowing_v<int&, long long>);
STATIC_CHECK(!iris::is_assignable_without_narrowing_v<double&, long long>);
STATIC_CHECK(!iris::is_assignable_without_narrowing_v<bool&, int*>);
STATIC_CHECK(!iris::is_assignable_without_narrowing_v<int&, to_long_long>); // after the conversion function
STATIC_CHECK(!iris::is_assignable_without_narrowing_v<int const&, int>);

// a class takes the value as the parameter of its assignment operator
STATIC_CHECK(iris::is_assignable_without_narrowing_v<port&, long long>);
STATIC_CHECK(iris::is_assignable_without_narrowing_v<assign_int&, long long>);
STATIC_CHECK(!iris::is_assignable_without_narrowing_v<assign_int&, std::string>);
}

TEST_CASE("conversion_overloads", "[type_traits]")
{
using int_or_long_long = iris::conversion_overloads<iris::conversion_overload<3, int>, iris::conversion_overload<5, long long>>;
STATIC_CHECK(iris::conversion_selects<int_or_long_long, int, 3>);
STATIC_CHECK(iris::conversion_selects<int_or_long_long, long long, 5>);
STATIC_CHECK(!iris::conversion_selects<int_or_long_long, int, 5>);
STATIC_CHECK(iris::conversion_selects<int_or_long_long, short, 3>); // a promotion
STATIC_CHECK(!iris::conversion_resolves<int_or_long_long, unsigned>); // ambiguous: both are conversions
STATIC_CHECK(!iris::conversion_resolves<int_or_long_long, std::string>);

using port_only = iris::conversion_overloads<iris::conversion_overload<0, port>>;
STATIC_CHECK(iris::conversion_selects<port_only, long long, 0>); // no narrowing check

STATIC_CHECK(!iris::conversion_resolves<iris::conversion_overloads<>, int>);
}
Loading