Skip to content

Commit 7a78082

Browse files
committed
✨ Add dereference
Problem: - There is no standard function object that calls unary `operator*`. Solution: - Add `dereference`.
1 parent 346cfb8 commit 7a78082

3 files changed

Lines changed: 60 additions & 10 deletions

File tree

docs/functional.adoc

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,24 @@ 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+
22+
=== `unary_plus`
23+
24+
`unary_plus` is a function object like
25+
https://en.cppreference.com/w/cpp/utility/functional/negate.html[`std::negate`],
26+
except it calls (unary) `operator+` instead of `operator-`.
27+
28+
It also has a specialization for `void` which is _transparent_ like that of
29+
https://en.cppreference.com/w/cpp/utility/functional/negate_void.html[`std::negate`].
30+
1331
=== `with_result_of`
1432

1533
`with_result_of` is a class that can be used for lazy evaluation.
@@ -35,11 +53,3 @@ v.emplace(0, stdx::with_result_of{make_S}); // this constructs S in-place thanks
3553
`with_result_of` can help to achieve in-place construction, effectively by deferring
3654
evaluation of function arguments.
3755

38-
=== `unary_plus`
39-
40-
`unary_plus` is a function object like
41-
https://en.cppreference.com/w/cpp/utility/functional/negate.html[`std::negate`],
42-
except it calls (unary) `operator+` instead of `operator-`.
43-
44-
It also has a specialization for `void` which is _transparent_ like that of
45-
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;
@@ -187,5 +191,25 @@ template <> struct unary_plus<void> {
187191
}
188192
};
189193

194+
// NOLINTBEGIN(modernize-use-constraints)
195+
template <typename T = void> struct dereference {
196+
template <typename U,
197+
typename = std::enable_if_t<is_same_unqualified_v<U, T>>>
198+
constexpr auto operator()(U &&u) const -> decltype(*std::forward<U>(u)) {
199+
return *std::forward<U>(u);
200+
}
201+
};
202+
// NOLINTEND(modernize-use-constraints)
203+
204+
template <> struct dereference<void> {
205+
using is_transparent = int;
206+
207+
template <typename T>
208+
constexpr auto operator()(T &&arg) const
209+
-> decltype(*std::forward<T>(arg)) {
210+
return *std::forward<T>(arg);
211+
}
212+
};
213+
190214
} // namespace v1
191215
} // namespace stdx

test/functional.cpp

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

1414
struct S {};
1515
constexpr auto operator+(S) { return 17; }
16+
constexpr auto operator*(S) { return 17; }
1617
} // namespace
1718

1819
TEST_CASE("unary_plus", "[functional]") {
@@ -28,3 +29,18 @@ TEST_CASE("unary_plus transparency", "[functional]") {
2829
TEST_CASE("unary_plus calls operator+", "[functional]") {
2930
STATIC_REQUIRE(stdx::unary_plus<>{}(S{}) == 17);
3031
}
32+
33+
TEST_CASE("dereference", "[functional]") {
34+
int x{17};
35+
CHECK(stdx::dereference<int *>{}(&x) == 17);
36+
CHECK(stdx::dereference<>{}(&x) == 17);
37+
}
38+
39+
TEST_CASE("dereference transparency", "[functional]") {
40+
STATIC_REQUIRE(not detect_is_transparent<stdx::dereference<int *>>);
41+
STATIC_REQUIRE(detect_is_transparent<stdx::dereference<>>);
42+
}
43+
44+
TEST_CASE("dereference calls operator*", "[functional]") {
45+
STATIC_REQUIRE(stdx::dereference<>{}(S{}) == 17);
46+
}

0 commit comments

Comments
 (0)