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 = decltype(std::declval<T&>() ? std::addressof(*std::declval<T&&>()) : nullptr);
21
22template <typename T>
23inline constexpr bool kIsPointerLike = meta::kIsDetected<IsPointerLike, T>;
24
25} // namespace impl
26
27template <typename Leaf>
28constexpr auto* GetIf(Leaf&& leaf) {
29 if constexpr (impl::kIsPointerLike<Leaf>) {
30 return leaf ? utils::GetIf(*std::forward<Leaf>(leaf)) : nullptr;
31 } else {
32 return std::addressof(std::forward<Leaf>(leaf));
33 }
34}
35
36/// @brief Dereferences a chain of indirections and compositions,
37/// returns nullptr if one of the chain elements is not set
38///
39/// @snippet universal/src/utils/get_if_test.cpp Sample Usage
40template <typename Root, typename Head, typename... Tail>
41constexpr auto* GetIf(Root&& root, Head&& head, Tail&&... tail) {
42 if constexpr (impl::kIsPointerLike<Root>) {
43 return root ? utils::GetIf(*std::forward<Root>(root), std::forward<Head>(head), std::forward<Tail>(tail)...)
44 : nullptr;
45 } else {
46 return utils::GetIf(
47 std::invoke(std::forward<Head>(head), std::forward<Root>(root)), std::forward<Tail>(tail)...
48 );
49 }
50}
51
52} // namespace utils
53
54USERVER_NAMESPACE_END