userver: userver/utils/get_if.hpp Source File
Loading...
Searching...
No Matches
get_if.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/utils/get_if.hpp
4/// @brief @copybrief utils::GetIf
5/// @ingroup userver_universal
6
7#include <functional>
8#include <memory>
9#include <utility>
10
11#include <userver/utils/meta_light.hpp>
12
13USERVER_NAMESPACE_BEGIN
14
15namespace utils {
16
17namespace impl {
18
19template <typename T>
20using IsPointerLike =
21 decltype(std::declval<T&>() ? std::addressof(*std::declval<T&&>())
22 : nullptr);
23
24template <typename T>
25inline constexpr bool kIsPointerLike = meta::kIsDetected<IsPointerLike, T>;
26
27} // namespace impl
28
29template <typename Leaf>
30constexpr auto* GetIf(Leaf&& leaf) {
31 if constexpr (impl::kIsPointerLike<Leaf>) {
32 return leaf ? utils::GetIf(*std::forward<Leaf>(leaf)) : nullptr;
33 } else {
34 return std::addressof(std::forward<Leaf>(leaf));
35 }
36}
37
38/// @brief Dereferences a chain of indirections and compositions,
39/// returns nullptr if one of the chain elements is not set
40///
41/// @snippet universal/src/utils/get_if_test.cpp Sample Usage
42template <typename Root, typename Head, typename... Tail>
43constexpr auto* GetIf(Root&& root, Head&& head, Tail&&... tail) {
44 if constexpr (impl::kIsPointerLike<Root>) {
45 return root ? utils::GetIf(*std::forward<Root>(root),
46 std::forward<Head>(head),
47 std::forward<Tail>(tail)...)
48 : nullptr;
49 } else {
50 return utils::GetIf(
51 std::invoke(std::forward<Head>(head), std::forward<Root>(root)),
52 std::forward<Tail>(tail)...);
53 }
54}
55
56} // namespace utils
57
58USERVER_NAMESPACE_END