Skip to content

Commit aed7977

Browse files
authored
Add value type support to as() and try_as() (#695)
1 parent 9ddc0bb commit aed7977

File tree

7 files changed

+371
-343
lines changed

7 files changed

+371
-343
lines changed

strings/base_com_ptr.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,17 @@ WINRT_EXPORT namespace winrt
133133
template <typename To>
134134
bool try_as(To& to) const noexcept
135135
{
136-
to = try_as<impl::wrapped_type_t<To>>();
137-
return static_cast<bool>(to);
136+
if constexpr (impl::is_com_interface_v<To> || !std::is_same_v<To, impl::wrapped_type_t<To>>)
137+
{
138+
to = try_as<impl::wrapped_type_t<To>>();
139+
return static_cast<bool>(to);
140+
}
141+
else
142+
{
143+
auto result = try_as<To>();
144+
to = result.has_value() ? result.value() : impl::empty_value<To>();
145+
return result.has_value();
146+
}
138147
}
139148

140149
hresult as(guid const& id, void** result) const noexcept

strings/base_meta.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -226,15 +226,6 @@ namespace winrt::impl
226226
template <typename T>
227227
using wrapped_type_t = typename wrapped_type<T>::type;
228228

229-
template <template <typename...> typename Trait, typename Enabler, typename... Args>
230-
struct is_detected : std::false_type {};
231-
232-
template <template <typename...> typename Trait, typename... Args>
233-
struct is_detected<Trait, std::void_t<Trait<Args...>>, Args...> : std::true_type {};
234-
235-
template <template <typename...> typename Trait, typename... Args>
236-
inline constexpr bool is_detected_v = std::is_same_v<typename is_detected<Trait, void, Args...>::type, std::true_type>;
237-
238229
template <typename ... Types>
239230
struct typelist {};
240231

strings/base_reference_produce.h

Lines changed: 91 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,95 @@ WINRT_EXPORT namespace winrt::Windows::Foundation
261261
}
262262
}
263263

264+
namespace winrt::impl
265+
{
266+
template <typename T, typename From>
267+
T unbox_value_type(From&& value)
268+
{
269+
static_assert(!is_com_interface_v<T>);
270+
271+
if (!value)
272+
{
273+
throw hresult_no_interface();
274+
}
275+
if constexpr (std::is_enum_v<T>)
276+
{
277+
if (auto temp = value.try_as<Windows::Foundation::IReference<T>>())
278+
{
279+
return temp.Value();
280+
}
281+
else
282+
{
283+
return static_cast<T>(value.as<Windows::Foundation::IReference<std::underlying_type_t<T>>>().Value());
284+
}
285+
}
286+
#ifdef WINRT_IMPL_IUNKNOWN_DEFINED
287+
else if constexpr (std::is_same_v<T, GUID>)
288+
{
289+
return value.as<Windows::Foundation::IReference<guid>>().Value();
290+
}
291+
#endif
292+
else
293+
{
294+
return value.as<Windows::Foundation::IReference<T>>().Value();
295+
}
296+
}
297+
298+
template <typename T, typename Ret = T, typename From, typename U>
299+
Ret unbox_value_type_or(From&& value, U&& default_value)
300+
{
301+
if constexpr (std::is_enum_v<T>)
302+
{
303+
if (auto temp = value.try_as<Windows::Foundation::IReference<T>>())
304+
{
305+
return temp.Value();
306+
}
307+
308+
if (auto temp = value.try_as<Windows::Foundation::IReference<std::underlying_type_t<T>>>())
309+
{
310+
return static_cast<T>(temp.Value());
311+
}
312+
}
313+
#ifdef WINRT_IMPL_IUNKNOWN_DEFINED
314+
else if constexpr (std::is_same_v<T, GUID>)
315+
{
316+
if (auto temp = value.try_as<Windows::Foundation::IReference<guid>>())
317+
{
318+
return temp.Value();
319+
}
320+
}
321+
#endif
322+
else
323+
{
324+
if (auto temp = value.try_as<Windows::Foundation::IReference<T>>())
325+
{
326+
return temp.Value();
327+
}
328+
}
329+
return default_value;
330+
}
331+
332+
template <typename To, typename From, std::enable_if_t<!is_com_interface_v<To>, int>>
333+
auto as(From* ptr)
334+
{
335+
if constexpr (impl::is_com_interface_v<From>)
336+
{
337+
return unbox_value_type<To>(reinterpret_cast<Windows::Foundation::IUnknown const&>(ptr));
338+
}
339+
else
340+
{
341+
return unbox_value_type<To>(reinterpret_cast<com_ptr<From> const&>(ptr));
342+
}
343+
}
344+
345+
template <typename To, typename From, std::enable_if_t<!is_com_interface_v<To>, int>>
346+
auto try_as(From* ptr) noexcept
347+
{
348+
using type = std::conditional_t<impl::is_com_interface_v<From>, Windows::Foundation::IUnknown, com_ptr<From>>;
349+
return unbox_value_type_or<To, std::optional<To>>(reinterpret_cast<type const&>(ptr), std::nullopt);
350+
}
351+
}
352+
264353
WINRT_EXPORT namespace winrt
265354
{
266355
inline Windows::Foundation::IInspectable box_value(param::hstring const& value)
@@ -290,31 +379,7 @@ WINRT_EXPORT namespace winrt
290379
}
291380
else
292381
{
293-
if (!value)
294-
{
295-
throw hresult_no_interface();
296-
}
297-
if constexpr (std::is_enum_v<T>)
298-
{
299-
if (auto temp = value.try_as<Windows::Foundation::IReference<T>>())
300-
{
301-
return temp.Value();
302-
}
303-
else
304-
{
305-
return static_cast<T>(value.as<Windows::Foundation::IReference<std::underlying_type_t<T>>>().Value());
306-
}
307-
}
308-
#ifdef WINRT_IMPL_IUNKNOWN_DEFINED
309-
else if constexpr (std::is_same_v<T, GUID>)
310-
{
311-
return value.as<Windows::Foundation::IReference<guid>>().Value();
312-
}
313-
#endif
314-
else
315-
{
316-
return value.as<Windows::Foundation::IReference<T>>().Value();
317-
}
382+
return impl::unbox_value_type<T>(value);
318383
}
319384
}
320385

@@ -344,36 +409,11 @@ WINRT_EXPORT namespace winrt
344409
return temp;
345410
}
346411
}
347-
else if constexpr (std::is_enum_v<T>)
348-
{
349-
if (auto temp = value.try_as<Windows::Foundation::IReference<T>>())
350-
{
351-
return temp.Value();
352-
}
353-
354-
if (auto temp = value.try_as<Windows::Foundation::IReference<std::underlying_type_t<T>>>())
355-
{
356-
return static_cast<T>(temp.Value());
357-
}
358-
}
359-
#ifdef WINRT_IMPL_IUNKNOWN_DEFINED
360-
else if constexpr (std::is_same_v<T, GUID>)
361-
{
362-
if (auto temp = value.try_as<Windows::Foundation::IReference<guid>>())
363-
{
364-
return temp.Value();
365-
}
366-
}
367-
#endif
368412
else
369413
{
370-
if (auto temp = value.try_as<Windows::Foundation::IReference<T>>())
371-
{
372-
return temp.Value();
373-
}
414+
return impl::unbox_value_type_or<T>(value, default_value);
374415
}
375416
}
376-
377417
return default_value;
378418
}
379419

strings/base_windows.h

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,22 @@ namespace winrt::impl
8181
return { result, take_ownership_from_abi };
8282
}
8383

84-
template <typename To, typename From>
84+
#ifdef WINRT_IMPL_IUNKNOWN_DEFINED
85+
template <typename T>
86+
struct is_com_interface : std::disjunction<std::is_base_of<Windows::Foundation::IUnknown, T>, std::is_base_of<unknown_abi, T>, is_implements<T>, std::is_base_of<::IUnknown, T>> {};
87+
#else
88+
template <typename T>
89+
struct is_com_interface : std::disjunction<std::is_base_of<Windows::Foundation::IUnknown, T>, std::is_base_of<unknown_abi, T>, is_implements<T>> {};
90+
#endif
91+
92+
template <typename T>
93+
inline constexpr bool is_com_interface_v = is_com_interface<T>::value;
94+
95+
// You must include <winrt/Windows.Foundation.h> to use this overload.
96+
template <typename To, typename From, std::enable_if_t<!is_com_interface_v<To>, int> = 0>
97+
auto as(From* ptr);
98+
99+
template <typename To, typename From, std::enable_if_t<is_com_interface_v<To>, int> = 0>
85100
com_ref<To> as(From* ptr)
86101
{
87102
#ifdef WINRT_DIAGNOSTICS
@@ -98,7 +113,11 @@ namespace winrt::impl
98113
return wrap_as_result<To>(result);
99114
}
100115

101-
template <typename To, typename From>
116+
// You must include <winrt/Windows.Foundation.h> to use this overload.
117+
template <typename To, typename From, std::enable_if_t<!is_com_interface_v<To>, int> = 0>
118+
auto try_as(From* ptr) noexcept;
119+
120+
template <typename To, typename From, std::enable_if_t<is_com_interface_v<To>, int> = 0>
102121
com_ref<To> try_as(From* ptr) noexcept
103122
{
104123
#ifdef WINRT_DIAGNOSTICS
@@ -197,8 +216,17 @@ WINRT_EXPORT namespace winrt::Windows::Foundation
197216
template <typename To>
198217
bool try_as(To& to) const noexcept
199218
{
200-
to = try_as<impl::wrapped_type_t<To>>();
201-
return static_cast<bool>(to);
219+
if constexpr (impl::is_com_interface_v<To> || !std::is_same_v<To, impl::wrapped_type_t<To>>)
220+
{
221+
to = try_as<impl::wrapped_type_t<To>>();
222+
return static_cast<bool>(to);
223+
}
224+
else
225+
{
226+
auto result = try_as<To>();
227+
to = result.has_value() ? result.value() : impl::empty_value<To>();
228+
return result.has_value();
229+
}
202230
}
203231

204232
hresult as(guid const& id, void** result) const noexcept

0 commit comments

Comments
 (0)