Skip to content
Open
Show file tree
Hide file tree
Changes from 12 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
49 changes: 41 additions & 8 deletions include/iris/type_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include <iris/requirements.hpp>

#include <concepts>
#include <type_traits>
#include <utility>

Expand Down Expand Up @@ -222,6 +223,45 @@ template<class T>
constexpr bool is_trivially_swappable_v = is_trivially_swappable<T>::value;


// P0870R7: is_convertible_without_narrowing
// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p0870r7.html
namespace detail {

template<class From, class To>
struct is_convertible_without_narrowing_impl
: std::false_type
{};

// void to void "conversion" is valid since `is_convertible` is defined
// as "returning `From` is valid for function whose return type is `To`?"
template<>
struct is_convertible_without_narrowing_impl<void, void>
: std::true_type
{};

template<class From, class To>
requires
requires (From&& x) {
{ std::type_identity_t<To[]>{std::forward<From>(x)} } -> std::same_as<To[1]>;
}
struct is_convertible_without_narrowing_impl<From, To>
: std::true_type
{};

} // namespace detail

template<class From, class To>
struct is_convertible_without_narrowing
: std::conjunction<
std::is_convertible<From, To>,
detail::is_convertible_without_narrowing_impl<From, To>
>
{};

template<class From, class To>
inline constexpr bool is_convertible_without_narrowing_v = is_convertible_without_narrowing<From, To>::value;


namespace detail {

template<std::size_t I, class Ti>
Expand All @@ -231,19 +271,12 @@ struct aggregate_initialize_tag
using type = Ti;
};

// This version works better than MSVC's, does not break IntelliSense or ReSharper
template<std::size_t I, class Ti>
struct aggregate_initialize_overload
Comment thread
yaito3014 marked this conversation as resolved.
Outdated
{
using TiA = Ti[];

// https://eel.is/c++draft/dcl.init.general#14
// https://eel.is/c++draft/dcl.init.list#3.4
// https://eel.is/c++draft/dcl.init.aggr#3

template<class T>
auto operator()(Ti, T&&) -> aggregate_initialize_tag<I, Ti>
requires requires(T&& t) { { TiA{std::forward<T>(t)} }; } // emulate `Ti x[] = {std::forward<T>(t)};`
requires is_convertible_without_narrowing_v<T, Ti>
Comment on lines 277 to +279

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the first parameter Ti can be omitted, as it existed for checking is_convertible by passing-by-value

@yaito3014 yaito3014 Mar 13, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, the Ti parameter cannot be omitted, since we should consider overload resolution for Ti including implicit conversion sequence's priority.

For example, constructing rvariant<int, long> from int should be resolved to index() == 0 though both int and long are equally convertible from int without narrowing. This is because identity conversion should occur prior to integral promotion in standard conversion.

{
return {}; // silence MSVC warning
}
Expand Down
Loading
Loading