HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
tryInvoke.h
Go to the documentation of this file.
1 //
2 // Copyright 2026 Pixar
3 //
4 // Licensed under the terms set forth in the LICENSE.txt file available at
5 // https://openusd.org/license.
6 //
7 #ifndef PXR_BASE_TF_TRY_INVOKE_H
8 #define PXR_BASE_TF_TRY_INVOKE_H
9 
10 /// \file tf/tryInvoke.h
11 
12 #include "pxr/pxr.h"
13 
14 #include <functional>
15 #include <optional>
16 #include <type_traits>
17 
18 /// Return the result type of \c TfTryInvoke<Ret> in the case where the function
19 /// was not invoked -- \c false if \p Ret is \c void, otherwise an empty \c
20 /// std::optional<Ret>. Call this when you need to produce the same result type
21 /// as \c TfTryInvoke in a context where the function was not called.
22 ///
23 /// \see TfTryInvoke
24 template <class Ret>
25 constexpr auto
27 {
28  if constexpr (std::is_void_v<Ret>) {
29  return false;
30  } else {
31  return std::optional<Ret>{};
32  }
33 }
34 
35 /// Invoke \p fn with \p args if \p fn is invocable with those arguments and
36 /// return a result that indicates both whether the call was made and, if so,
37 /// what it returned.
38 ///
39 /// The template parameter \p Ret specifies the expected return type of
40 /// \p fn:
41 /// - If \p fn is invocable and \p Ret is non-void, invoke \p fn and return \c
42 /// std::optional<Ret> containing the result.
43 /// - If \p fn is invocable and \p Ret is void, invoke \p fn and return \c true.
44 /// - If \p fn is not invocable with \p args, return \c TfNotInvoked<Ret>() --
45 /// an empty \c std::optional<Ret> or \c false.
46 ///
47 /// The return value is always truthy if \p fn was invoked and falsy if it was
48 /// not, regardless of whether \p Ret is void.
49 ///
50 /// Use this to build operations over heterogeneous collections where a callable
51 /// may only handle a subset of element types:
52 ///
53 /// \code
54 /// auto process = [](std::string const &s) { return s.size(); };
55 ///
56 /// // Invocable -- returns optional<size_t> containing the result.
57 /// auto r1 = TfTryInvoke<size_t>(process, std::string("hello"));
58 /// TF_AXIOM(r1 && *r1 == 5);
59 ///
60 /// // Not invocable -- returns empty optional<size_t>.
61 /// auto r2 = TfTryInvoke<size_t>(process, 42);
62 /// TF_AXIOM(!r2);
63 /// \endcode
64 ///
65 /// \see TfNotInvoked
66 template <class Ret, class Fn, class... Args>
67 auto
68 TfTryInvoke(Fn &&fn, Args &&...args)
69 {
70  if constexpr (std::is_invocable_v<Fn, Args...>) {
71  if constexpr (std::is_void_v<Ret>) {
72  std::invoke(std::forward<Fn>(fn), std::forward<Args>(args)...);
73  return true;
74  } else {
75  return std::optional<Ret>(
76  std::invoke(std::forward<Fn>(fn), std::forward<Args>(args)...));
77  }
78  } else {
79  return TfNotInvoked<Ret>();
80  }
81 }
82 
83 #endif // PXR_BASE_TF_TRY_INVOKE_H
auto TfTryInvoke(Fn &&fn, Args &&...args)
Definition: tryInvoke.h:68
constexpr auto TfNotInvoked()
Definition: tryInvoke.h:26
**If you just want to fire and args
Definition: thread.h:618
int invoke(const Func &taskFunc1, Rest...taskFuncN)
Definition: Invoke.h:64