Funktioniert invoke_result_t für std::apply mit einem Tuple
-
Hi,
für
std::invokekann ich mitstd::invoke_result_tden Rückgabetyp ermitteln und zum Beispiel mitif constexprin Abhängigkeit von dem return type unterschiedliche Dinge machen.Ein kurzer Test scheint zu ergeben, dass
std::invoke_result_tauch funktioniert, wenn man eine Funktion mitstd::applyaufruft 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::applyzu 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::applymacht 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.