- 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.idlnamespaceSample{runtimeclass Thing{staticAccept([variant] Object value)} } // C++/WinRT without [variant] supportwinrt::Thing::Accept(winrt::box_value(3)); // C++/WinRT with [variant] supportwinrt::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.
structwinrt::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
structwinrt::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> structvariant{template<typename U> variant(U&& arg) : value(box_value(arg)){} IInspectable value}; template<> structvariant<false>{variant(Insp const& arg) : value(&arg){} constvoid* 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.