Skip to content
This repository was archived by the owner on Jan 29, 2026. It is now read-only.

Commit 1f2037f

Browse files
authored
Replace macro PRO_DEF_WEAK_DISPATCH with class template weak_dispatch (#224)
1 parent 248e8cf commit 1f2037f

3 files changed

Lines changed: 55 additions & 35 deletions

File tree

proxy.h

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66

77
#include <cassert>
88
#include <cstddef>
9+
#include <cstdlib>
910
#include <bit>
1011
#include <concepts>
12+
#include <exception>
1113
#include <initializer_list>
1214
#include <limits>
1315
#include <memory>
@@ -16,9 +18,6 @@
1618
#include <utility>
1719

1820
#ifdef __cpp_rtti
19-
#ifndef __cpp_exceptions
20-
#include <cstdlib> // For std::abort() when "throw" is not available
21-
#endif // __cpp_exceptions
2221
#include <optional>
2322
#include <typeinfo>
2423
#endif // __cpp_rtti
@@ -31,6 +30,12 @@
3130
#error "Proxy requires C++20 attribute no_unique_address"
3231
#endif
3332

33+
#ifdef __cpp_exceptions
34+
#define ___PRO_THROW(...) throw __VA_ARGS__
35+
#else
36+
#define ___PRO_THROW(...) std::abort()
37+
#endif // __cpp_exceptions
38+
3439
#ifdef _MSC_VER
3540
#define ___PRO_ENFORCE_EBO __declspec(empty_bases)
3641
#else
@@ -1256,7 +1261,11 @@ using proxy_view = proxy<observer_facade<F>>;
12561261
accessor() noexcept { ::std::ignore = &accessor::__VA_ARGS__; })
12571262

12581263
#ifdef __cpp_rtti
1259-
struct bad_proxy_cast : std::bad_cast {};
1264+
class bad_proxy_cast : public std::bad_cast {
1265+
public:
1266+
bad_proxy_cast() noexcept = default;
1267+
char const* what() const noexcept override { return "pro::bad_proxy_cast"; }
1268+
};
12601269
#endif // __cpp_rtti
12611270

12621271
namespace details {
@@ -1554,12 +1563,6 @@ template <std::size_t N>
15541563
sign(const char (&str)[N]) -> sign<N>;
15551564

15561565
#ifdef __cpp_rtti
1557-
#ifdef __cpp_exceptions
1558-
#define ___PRO_THROW(...) throw __VA_ARGS__
1559-
#else
1560-
#define ___PRO_THROW(...) std::abort()
1561-
#endif // __cpp_exceptions
1562-
15631566
struct proxy_cast_context {
15641567
const std::type_info* type_ptr;
15651568
bool is_ref;
@@ -1657,9 +1660,21 @@ ___PRO_DEBUG(
16571660

16581661
const std::type_info* info;
16591662
};
1660-
#undef ___PRO_THROW
16611663
#endif // __cpp_rtti
16621664

1665+
struct wildcard {
1666+
wildcard() = delete;
1667+
1668+
template <class T>
1669+
[[noreturn]] operator T() {
1670+
#ifdef __cpp_lib_unreachable
1671+
std::unreachable();
1672+
#else
1673+
std::abort();
1674+
#endif // __cpp_lib_unreachable
1675+
}
1676+
};
1677+
16631678
} // namespace details
16641679

16651680
template <class Cs, class Rs, proxiable_ptr_constraints C>
@@ -1969,6 +1984,20 @@ struct explicit_conversion_dispatch : details::cast_dispatch_base<true, false> {
19691984
};
19701985
using conversion_dispatch = explicit_conversion_dispatch;
19711986

1987+
class not_implemented : public std::exception {
1988+
public:
1989+
not_implemented() noexcept = default;
1990+
char const* what() const noexcept override { return "pro::not_implemented"; }
1991+
};
1992+
1993+
template <class D>
1994+
struct weak_dispatch : D {
1995+
using D::operator();
1996+
template <class... Args>
1997+
[[noreturn]] details::wildcard operator()(std::nullptr_t, Args&&...)
1998+
{ ___PRO_THROW(not_implemented{}); }
1999+
};
2000+
19722001
#define ___PRO_EXPAND_IMPL(__X) __X
19732002
#define ___PRO_EXPAND_MACRO_IMPL( \
19742003
__MACRO, __1, __2, __3, __NAME, ...) \
@@ -2049,7 +2078,8 @@ ___PRO_DEBUG( \
20492078
___PRO_EXPAND_MACRO(___PRO_DEF_FREE_AS_MEM_DISPATCH, __NAME, __VA_ARGS__)
20502079

20512080
#define PRO_DEF_WEAK_DISPATCH(__NAME, __D, __FUNC) \
2052-
struct __NAME : __D { \
2081+
struct [[deprecated("'PRO_DEF_WEAK_DISPATCH' is deprecated. " \
2082+
"Use pro::weak_dispatch<" #__D "> instead.")]] __NAME : __D { \
20532083
using __D::operator(); \
20542084
template <class... __Args> \
20552085
decltype(auto) operator()(::std::nullptr_t, __Args&&... __args) \
@@ -2058,6 +2088,7 @@ ___PRO_DEBUG( \
20582088

20592089
} // namespace pro
20602090

2091+
#undef ___PRO_THROW
20612092
#undef ___PRO_NO_UNIQUE_ADDRESS_ATTRIBUTE
20622093

20632094
#endif // _MSFT_PROXY_

tests/freestanding/proxy_freestanding_tests.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include "proxy.h"
66

7+
constexpr unsigned DefaultHash = -1;
78
unsigned GetHash(int v) { return static_cast<unsigned>(v + 3) * 31; }
89
unsigned GetHash(double v) { return static_cast<unsigned>(v * v + 5) * 87; }
910
unsigned GetHash(const char* v) {
@@ -13,12 +14,11 @@ unsigned GetHash(const char* v) {
1314
}
1415
return result;
1516
}
16-
unsigned GetDefaultHash() { return -1; }
17+
unsigned GetHash(std::nullptr_t) { return DefaultHash; }
1718

1819
PRO_DEF_FREE_DISPATCH(FreeGetHash, GetHash);
19-
PRO_DEF_WEAK_DISPATCH(WeakFreeGetHash, FreeGetHash, GetDefaultHash);
2020
struct Hashable : pro::facade_builder
21-
::add_convention<WeakFreeGetHash, unsigned()>
21+
::add_convention<FreeGetHash, unsigned()>
2222
::build {};
2323

2424
extern "C" int main() {
@@ -40,7 +40,7 @@ extern "C" int main() {
4040
return 1;
4141
}
4242
p = &t;
43-
if (GetHash(*p) != GetDefaultHash()) {
43+
if (GetHash(*p) != DefaultHash) {
4444
return 1;
4545
}
4646
return 0;

tests/proxy_invocation_tests.cpp

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,10 @@ struct Callable : pro::facade_builder
3636
::add_facade<MovableCallable<Os...>>
3737
::build {};
3838

39-
struct Wildcard {
40-
template <class T>
41-
operator T() const noexcept { std::terminate(); }
42-
};
43-
44-
Wildcard NotImplemented(auto&&...) { throw std::runtime_error{ "Not implemented!" }; }
45-
46-
PRO_DEF_WEAK_DISPATCH(WeakOpCall, pro::operator_dispatch<"()">, NotImplemented);
4739
template <class... Os>
4840
struct WeakCallable : pro::facade_builder
4941
::support_copy<pro::constraint_level::nontrivial>
50-
::add_convention<WeakOpCall, Os...>
42+
::add_convention<pro::weak_dispatch<pro::operator_dispatch<"()">>, Os...>
5143
::build {};
5244

5345
PRO_DEF_FREE_DISPATCH(FreeSize, std::ranges::size, Size);
@@ -77,10 +69,9 @@ struct Container : pro::facade_builder
7769
::build {};
7870

7971
PRO_DEF_MEM_DISPATCH(MemAt, at, at);
80-
PRO_DEF_WEAK_DISPATCH(MemAtWeak, MemAt, NotImplemented);
8172

8273
struct ResourceDictionary : pro::facade_builder
83-
::add_convention<MemAtWeak, std::string(int)>
74+
::add_convention<pro::weak_dispatch<MemAt>, std::string(int)>
8475
::build {};
8576

8677
template <class F, class T>
@@ -101,12 +92,12 @@ struct Weak : pro::facade_builder
10192
::build {};
10293

10394
template <class F, class T>
104-
auto GetWeakImpl(const std::shared_ptr<T>& p) { return pro::make_proxy<Weak<F>, std::weak_ptr<T>>(p); }
105-
95+
pro::proxy<Weak<F>> GetWeakImpl(const std::shared_ptr<T>& p) { return pro::make_proxy<Weak<F>, std::weak_ptr<T>>(p); }
10696
template <class F>
107-
PRO_DEF_FREE_DISPATCH(FreeGetWeakImpl, GetWeakImpl<F>, GetWeak);
97+
pro::proxy<Weak<F>> GetWeakImpl(std::nullptr_t) { return nullptr; }
98+
10899
template <class F>
109-
PRO_DEF_WEAK_DISPATCH(FreeGetWeak, FreeGetWeakImpl<F>, std::nullptr_t);
100+
PRO_DEF_FREE_DISPATCH(FreeGetWeak, GetWeakImpl<F>, GetWeak);
110101

111102
struct SharedStringable : pro::facade_builder
112103
::add_facade<utils::spec::Stringable>
@@ -272,9 +263,8 @@ TEST(ProxyInvocationTests, TestMemberDispatchDefault) {
272263
bool exception_thrown = false;
273264
try {
274265
p->at(0);
275-
} catch (const std::runtime_error& e) {
266+
} catch (const pro::not_implemented&) {
276267
exception_thrown = true;
277-
ASSERT_EQ(static_cast<std::string>(e.what()), "Not implemented!");
278268
}
279269
ASSERT_TRUE(exception_thrown);
280270
}
@@ -292,9 +282,8 @@ TEST(ProxyInvocationTests, TestFreeDispatchDefault) {
292282
auto p = pro::make_proxy<details::WeakCallable<void()>>(123);
293283
try {
294284
(*p)();
295-
} catch (const std::runtime_error& e) {
285+
} catch (const pro::not_implemented&) {
296286
exception_thrown = true;
297-
ASSERT_EQ(static_cast<std::string>(e.what()), "Not implemented!");
298287
}
299288
ASSERT_TRUE(exception_thrown);
300289
}

0 commit comments

Comments
 (0)