Skip to content

Commit a8a870c

Browse files
committed
✨ Add dereference
Problem: - There is no standard function object that calls unary `operator*`. Solution: - Add `dereference`.
1 parent 5e5ffee commit a8a870c

4 files changed

Lines changed: 62 additions & 10 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ target_sources(
8989
include/stdx/utility.hpp)
9090

9191
if(PROJECT_IS_TOP_LEVEL)
92+
include(CTest)
9293
add_docs(docs)
9394
add_subdirectory(test)
9495
clang_tidy_interface(stdx)

docs/functional.adoc

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,15 @@ NOTE: https://wg21.link/P2714[P2714] added the ability (in C\\++26) to use a
1010
non-type template parameter for the bound function; this works for function
1111
pointers in C++17, and also for lambda expressions in C++20 and beyond.
1212

13+
=== `dereference`
14+
15+
`dereference` is a function object like
16+
https://en.cppreference.com/w/cpp/utility/functional/negate.html[`std::negate`],
17+
except it calls (unary) `operator*` instead of `operator-`.
18+
19+
It also has a specialization for `void` which is _transparent_ like that of
20+
https://en.cppreference.com/w/cpp/utility/functional/negate_void.html[`std::negate`].
21+
1322
=== `safe_identity`
1423

1524
`safe_identity` is a function object (of type `safe_identity_t`) similar
@@ -34,6 +43,16 @@ NOTE: In standard usage, the type is `std::identity` and we must instantiate it
3443
to use it; in `stdx`, the type is `safe_identity_t` and `safe_identity` is a
3544
`constexpr inline` variable of that type.
3645

46+
=== `unary_plus`
47+
48+
`unary_plus` is a function object like
49+
https://en.cppreference.com/w/cpp/utility/functional/negate.html[`std::negate`],
50+
except it calls (unary) `operator+` instead of `operator-`.
51+
52+
It also has a specialization for `void` which is _transparent_ like that of
53+
https://en.cppreference.com/w/cpp/utility/functional/negate_void.html[`std::negate`].
54+
>>>>>>> 7a78082 (:sparkles: Add `dereference`)
55+
3756
=== `with_result_of`
3857

3958
`with_result_of` is a class that can be used for lazy evaluation.
@@ -59,11 +78,3 @@ v.emplace(0, stdx::with_result_of{make_S}); // this constructs S in-place thanks
5978
`with_result_of` can help to achieve in-place construction, effectively by deferring
6079
evaluation of function arguments.
6180

62-
=== `unary_plus`
63-
64-
`unary_plus` is a function object like
65-
https://en.cppreference.com/w/cpp/utility/functional/negate.html[`std::negate`],
66-
except it calls (unary) `operator+` instead of `operator-`.
67-
68-
It also has a specialization for `void` which is _transparent_ like that of
69-
https://en.cppreference.com/w/cpp/utility/functional/negate_void.html[`std::negate`].

include/stdx/functional.hpp

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,11 +171,15 @@ template <auto F, typename... Args> constexpr auto bind_back(Args &&...args) {
171171

172172
#endif
173173

174+
// NOLINTBEGIN(modernize-use-constraints)
174175
template <typename T = void> struct unary_plus {
175-
constexpr auto operator()(T const &arg) const -> decltype(+arg) {
176-
return +arg;
176+
template <typename U,
177+
typename = std::enable_if_t<is_same_unqualified_v<U, T>>>
178+
constexpr auto operator()(U &&u) const -> decltype(+std::forward<U>(u)) {
179+
return +std::forward<U>(u);
177180
}
178181
};
182+
// NOLINTEND(modernize-use-constraints)
179183

180184
template <> struct unary_plus<void> {
181185
using is_transparent = int;
@@ -195,5 +199,25 @@ constexpr inline struct safe_identity_t {
195199
return T(std::forward<T>(t));
196200
}
197201
} safe_identity;
202+
203+
// NOLINTBEGIN(modernize-use-constraints)
204+
template <typename T = void> struct dereference {
205+
template <typename U,
206+
typename = std::enable_if_t<is_same_unqualified_v<U, T>>>
207+
constexpr auto operator()(U &&u) const -> decltype(*std::forward<U>(u)) {
208+
return *std::forward<U>(u);
209+
}
210+
};
211+
// NOLINTEND(modernize-use-constraints)
212+
213+
template <> struct dereference<void> {
214+
using is_transparent = int;
215+
216+
template <typename T>
217+
constexpr auto operator()(T &&arg) const
218+
-> decltype(*std::forward<T>(arg)) {
219+
return *std::forward<T>(arg);
220+
}
221+
};
198222
} // namespace v1
199223
} // namespace stdx

test/functional.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ constexpr auto
1616

1717
struct S {};
1818
constexpr auto operator+(S) { return 17; }
19+
constexpr auto operator*(S) { return 28; }
1920
} // namespace
2021

2122
TEST_CASE("unary_plus", "[functional]") {
@@ -89,3 +90,18 @@ TEST_CASE("safe_identity cvref categories", "[functional]") {
8990
declval<int const volatile &&>())),
9091
int>);
9192
}
93+
94+
TEST_CASE("dereference", "[functional]") {
95+
int x{28};
96+
CHECK(stdx::dereference<int *>{}(&x) == 28);
97+
CHECK(stdx::dereference<>{}(&x) == 28);
98+
}
99+
100+
TEST_CASE("dereference transparency", "[functional]") {
101+
STATIC_REQUIRE(not detect_is_transparent<stdx::dereference<int *>>);
102+
STATIC_REQUIRE(detect_is_transparent<stdx::dereference<>>);
103+
}
104+
105+
TEST_CASE("dereference calls operator*", "[functional]") {
106+
STATIC_REQUIRE(stdx::dereference<>{}(S{}) == 28);
107+
}

0 commit comments

Comments
 (0)