diff --git a/CMakeLists.txt b/CMakeLists.txt index c91fa2d..b5dba32 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,6 +89,7 @@ target_sources( include/stdx/utility.hpp) if(PROJECT_IS_TOP_LEVEL) + include(CTest) add_docs(docs) add_subdirectory(test) clang_tidy_interface(stdx) diff --git a/docs/functional.adoc b/docs/functional.adoc index e6e5cc5..c628082 100644 --- a/docs/functional.adoc +++ b/docs/functional.adoc @@ -10,6 +10,15 @@ NOTE: https://wg21.link/P2714[P2714] added the ability (in C\\++26) to use a non-type template parameter for the bound function; this works for function pointers in C++17, and also for lambda expressions in C++20 and beyond. +=== `dereference` + +`dereference` is a function object like +https://en.cppreference.com/w/cpp/utility/functional/negate.html[`std::negate`], +except it calls (unary) `operator*` instead of `operator-`. + +It also has a specialization for `void` which is _transparent_ like that of +https://en.cppreference.com/w/cpp/utility/functional/negate_void.html[`std::negate`]. + === `safe_identity` `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 to use it; in `stdx`, the type is `safe_identity_t` and `safe_identity` is a `constexpr inline` variable of that type. +=== `unary_plus` + +`unary_plus` is a function object like +https://en.cppreference.com/w/cpp/utility/functional/negate.html[`std::negate`], +except it calls (unary) `operator+` instead of `operator-`. + +It also has a specialization for `void` which is _transparent_ like that of +https://en.cppreference.com/w/cpp/utility/functional/negate_void.html[`std::negate`]. +>>>>>>> 7a78082 (:sparkles: Add `dereference`) + === `with_result_of` `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 `with_result_of` can help to achieve in-place construction, effectively by deferring evaluation of function arguments. -=== `unary_plus` - -`unary_plus` is a function object like -https://en.cppreference.com/w/cpp/utility/functional/negate.html[`std::negate`], -except it calls (unary) `operator+` instead of `operator-`. - -It also has a specialization for `void` which is _transparent_ like that of -https://en.cppreference.com/w/cpp/utility/functional/negate_void.html[`std::negate`]. diff --git a/include/stdx/functional.hpp b/include/stdx/functional.hpp index 1d5da4f..18e7132 100644 --- a/include/stdx/functional.hpp +++ b/include/stdx/functional.hpp @@ -171,11 +171,15 @@ template constexpr auto bind_back(Args &&...args) { #endif +// NOLINTBEGIN(modernize-use-constraints) template struct unary_plus { - constexpr auto operator()(T const &arg) const -> decltype(+arg) { - return +arg; + template >> + constexpr auto operator()(U &&u) const -> decltype(+std::forward(u)) { + return +std::forward(u); } }; +// NOLINTEND(modernize-use-constraints) template <> struct unary_plus { using is_transparent = int; @@ -195,5 +199,25 @@ constexpr inline struct safe_identity_t { return T(std::forward(t)); } } safe_identity; + +// NOLINTBEGIN(modernize-use-constraints) +template struct dereference { + template >> + constexpr auto operator()(U &&u) const -> decltype(*std::forward(u)) { + return *std::forward(u); + } +}; +// NOLINTEND(modernize-use-constraints) + +template <> struct dereference { + using is_transparent = int; + + template + constexpr auto operator()(T &&arg) const + -> decltype(*std::forward(arg)) { + return *std::forward(arg); + } +}; } // namespace v1 } // namespace stdx diff --git a/test/functional.cpp b/test/functional.cpp index 9b728f6..858ab98 100644 --- a/test/functional.cpp +++ b/test/functional.cpp @@ -16,6 +16,7 @@ constexpr auto struct S {}; constexpr auto operator+(S) { return 17; } +constexpr auto operator*(S) { return 28; } } // namespace TEST_CASE("unary_plus", "[functional]") { @@ -89,3 +90,18 @@ TEST_CASE("safe_identity cvref categories", "[functional]") { declval())), int>); } + +TEST_CASE("dereference", "[functional]") { + int x{28}; + CHECK(stdx::dereference{}(&x) == 28); + CHECK(stdx::dereference<>{}(&x) == 28); +} + +TEST_CASE("dereference transparency", "[functional]") { + STATIC_REQUIRE(not detect_is_transparent>); + STATIC_REQUIRE(detect_is_transparent>); +} + +TEST_CASE("dereference calls operator*", "[functional]") { + STATIC_REQUIRE(stdx::dereference<>{}(S{}) == 28); +}