-
Notifications
You must be signed in to change notification settings - Fork 263
Description
Version
2.0.250303.1
Summary
The [variant] and [hasvariant] parameter attributes are hints that scalars should be auto-boxed. C++/WinRT does not take advantage of this right now.
Reproducible example
// Sample.idl
namespace Sample
{
runtimeclass Thing
{
static Accept([variant] Object value);
}
}
// C++/WinRT without [variant] support
winrt::Thing::Accept(winrt::box_value(3));
// C++/WinRT with [variant] support
winrt::Thing::Accept(3);Expected behavior
The value "3" to be accepted without boxing.
Actual behavior
Compiler error saying that 3 cannot be converted to IInspectable const&.
Additional comments
Sketch is to create a new parameter type winrt::param::variant.
Option 1: Simple but expensive.
struct winrt::param::variant
{
template<typename T>
variant(T&& arg) : value(box_value(arg)) {}
IInspectable value;
};
consume_Blah(winrt::param::variant arg);This adds an AddRef/Release to the cost of an IInspectable parameter.
Option 2:
struct winrt::param::variant
{
template<typename = std::enable_if_t<std::is_base_of_v<Windows::Foundation::IInspectable, std::decay_t<T>>>
variant(T&& arg) : value(get_abi(arg)) {}
template<typename U>
variant(U&& arg) : temp(box_value(arg)) { value = get_abi(temp); }
void* value;
IInspectable temp;
};
consume_Blah(winrt::param::variant arg);
This avoids the AddRef/Release for inbound IInspectables, but still costs a null check when the variant destructs (assuming the compiler can't optimize it out).
Option 3: Overload the consumer to accept either IInspectable or param::boxed_value
struct winrt::param::boxed_value
{
template<typename U>
variant(U&& arg) : value(box_value(arg)) { }
IInspectable value;
};
consume_Blah(IInspectable arg);
consume_Blah(winrt::param::boxed_arg arg);This avoids the overhead in the case where the caller passes an IInspectable, but it results in 2^N overload explosion.
Option 4: Use CTAD
template<bool boxed>
struct variant
{
template<typename U>
variant(U&& arg) : value(box_value(arg)) { }
IInspectable value;
};
template<>
struct variant<false>
{
variant(Insp const& arg) : value(&arg) { }
const void* value;
};
template<typename T, typename = std::enable_if_t<!std::is_base_of_v<IInspectable, std::decay_t<T>>, int>>
variant(T&&) -> variant<true>;
template<typename T, typename = std::enable_if_t<std::is_base_of_v<IInspectable, std::decay_t<T>>, void>>
variant(T&&) -> variant<false>;
template<bool boxed1>
consume_Blah(winrt::param::varaint<boxed1> arg);This still has 2^N explosion (since each variant parameter gets a different bool parameter for its variant) but you only emit the code once.