From 57c7a6d04086fc5a31444bc5001d935a05ee1869 Mon Sep 17 00:00:00 2001 From: Nana Sakisaka <1901813+saki7@users.noreply.github.com> Date: Thu, 1 Oct 2026 15:53:31 +0900 Subject: [PATCH] Add more narrowing utils --- include/iris/type_traits.hpp | 38 ++++++++++++++++++++++++++++++++++++ test/narrowing.cpp | 32 ++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/include/iris/type_traits.hpp b/include/iris/type_traits.hpp index 4a9ece7..b15be1a 100644 --- a/include/iris/type_traits.hpp +++ b/include/iris/type_traits.hpp @@ -314,6 +314,24 @@ struct is_convertible_without_narrowing template inline constexpr bool is_convertible_without_narrowing_v = is_convertible_without_narrowing::value; +template +struct is_assignable_without_narrowing : std::false_type +{}; + +template + requires + std::is_assignable_v && + ( + !std::is_scalar_v> || + is_convertible_without_narrowing_v> + ) +struct is_assignable_without_narrowing + : std::true_type +{}; + +template +inline constexpr bool is_assignable_without_narrowing_v = is_assignable_without_narrowing::value; + // ---------------------------------------------- namespace detail { @@ -552,6 +570,26 @@ struct no_narrowing_resolution< template struct no_narrowing_resolution : detail::no_narrowing_resolution {}; +template +struct conversion_overload +{ + static std::integral_constant select(T); // not defined +}; + +template +struct conversion_overloads : Overloads... +{ + using Overloads::select...; +}; + +template +concept conversion_resolves = requires { Overloads::select(std::declval()); }; + +template +concept conversion_selects = requires { + { Overloads::select(std::declval()) } -> std::same_as>; +}; + // ---------------------------------------------- namespace detail { diff --git a/test/narrowing.cpp b/test/narrowing.cpp index a4f2276..fc696ec 100644 --- a/test/narrowing.cpp +++ b/test/narrowing.cpp @@ -425,3 +425,35 @@ TEST_CASE("is_assignable_without_any_narrowing", "[type_traits]") STATIC_CHECK(!iris::is_assignable_without_any_narrowing_v); // initializer-list assignment } + +TEST_CASE("is_assignable_without_narrowing", "[type_traits]") +{ + STATIC_CHECK(iris::is_assignable_without_narrowing_v); + STATIC_CHECK(iris::is_assignable_without_narrowing_v); + STATIC_CHECK(!iris::is_assignable_without_narrowing_v); + STATIC_CHECK(!iris::is_assignable_without_narrowing_v); + STATIC_CHECK(!iris::is_assignable_without_narrowing_v); + STATIC_CHECK(!iris::is_assignable_without_narrowing_v); // after the conversion function + STATIC_CHECK(!iris::is_assignable_without_narrowing_v); + + // a class takes the value as the parameter of its assignment operator + STATIC_CHECK(iris::is_assignable_without_narrowing_v); + STATIC_CHECK(iris::is_assignable_without_narrowing_v); + STATIC_CHECK(!iris::is_assignable_without_narrowing_v); +} + +TEST_CASE("conversion_overloads", "[type_traits]") +{ + using int_or_long_long = iris::conversion_overloads, iris::conversion_overload<5, long long>>; + STATIC_CHECK(iris::conversion_selects); + STATIC_CHECK(iris::conversion_selects); + STATIC_CHECK(!iris::conversion_selects); + STATIC_CHECK(iris::conversion_selects); // a promotion + STATIC_CHECK(!iris::conversion_resolves); // ambiguous: both are conversions + STATIC_CHECK(!iris::conversion_resolves); + + using port_only = iris::conversion_overloads>; + STATIC_CHECK(iris::conversion_selects); // no narrowing check + + STATIC_CHECK(!iris::conversion_resolves, int>); +}