Funktioniert invoke_result_t für std::apply mit einem Tuple
-
Hi,
für
std::invoke
kann ich mitstd::invoke_result_t
den Rückgabetyp ermitteln und zum Beispiel mitif constexpr
in Abhängigkeit von dem return type unterschiedliche Dinge machen.Ein kurzer Test scheint zu ergeben, dass
std::invoke_result_t
auch funktioniert, wenn man eine Funktion mitstd::apply
aufruft und ein Tuple übergibt.Die Referenz von inovke_result sagt "Deduces the return type of an INVOKE expression at compile time."
Die Referenz von std::apply sagt "Invoke the Callable object f with the elements of t as arguments."Macht das
std::apply
zu einer "invoke expression"? Funktioniert der Tuple Overload in meinem Beispiel dann immer?Hier das Beispiel, das mit Visual Studio (/std:c++latest) kompiliert und das erwartete zurück liefert :
#include <print> #include <optional> template <typename R, typename F, typename ... Args> R DoInvoke(F&& f, Args&&... args) { using retType = std::invoke_result_t<F, Args...>; if constexpr (std::is_same_v<retType, std::optional<R>>) { return std::invoke(f, args...).value_or(0.0); } else { return std::invoke(f, args...); } } //Overload for tuple template <typename R, typename F, typename ... Args> R DoInvoke(F&& f, std::tuple<Args...> t) { using retType = std::invoke_result_t<F, Args...>; if constexpr (std::is_same_v<retType, std::optional<R>>) { return std::apply(f, t).value_or(0.0); } else { return std::apply(f, t); } } int main() { auto res = DoInvoke<int>([](int a, int b) { return a + b; }, 1, 1); auto res2 = DoInvoke<double>([](double a, double b) { return b != 0.0 ? std::optional(a/b) : std::nullopt; }, 1, 0); auto res3 = DoInvoke<int>([](int a, int b) { return a + b; }, std::make_tuple(1, 1)); auto res4 = DoInvoke<double>([](double a, double b) { return b != 0.0 ? std::optional(a / b) : std::nullopt; }, std::make_tuple(1, 0)); std::println("{}", res ); std::println("{}", res2); std::println("{}", res3); std::println("{}", res4); return 0; }
-
std::apply
macht doch nichts anderes, als die Tuple-Elemente einzeln als Parameter an den Funktor zu übergeben. In deinem Test mitusing retType = std::invoke_result_t<F, Args...>
machst du ja exakt das gleiche (auch wenn du hier die value-category vernachlässigst), also warum sollte das nicht das richtige Ergebnis liefern?
-
Ach, danke für den Tritt in die richtige Richtung.
Mein Gedanke war, das mit Tuple
f(t)
ja nicht funktioniert. AberArgs...
für das Tuple oder die direkten Parameter ist ja identisch. Wenn das für die direkten Parameter funktioniert muss das auch für die Typen im Tuple funktionieren.