Issue
I am trying to write a method decorator timing
that I intend to use as follows:
auto res = timing(my_func, arg1, arg2);
where res
contains the result of my_func(arg1, arg2)
.
My implementation of timing
looks like this:
template <typename FunctionT, typename ...ArgT, typename ResultT>
ResultT timing(FunctionT fn, ArgT... args) {
// do something here
ResultT result = fn(args...);
// do something else here
return result;
}
However, this doesn't compile because G++ cannot deduct ResultT
of the above call, for example the following minimal NOT working example:
#include <iostream>
// put timing method here
float my_func(float f, float g) {
return f + g;
}
int main() {
auto res = timing(my_func, 0.f, 3.f);
std::cout << "Result is: " << res;
}
throws the following compiler error when compiled with g++ test.cpp
:
test.cpp: In function ‘int main()’:
test.cpp:19:22: error: no matching function for call to ‘timing(float (&)(float, float), float, float)’
19 | auto res = timing(my_func, 0.f, 3.f);
| ~~~~~~^~~~~~~~~~~~~~~~~~~
test.cpp:5:9: note: candidate: ‘template<class FunctionT, class ... ArgT, class ResultT> ResultT timing(FunctionT, ArgT ...)’
5 | ResultT timing(FunctionT fn, ArgT... args) {
| ^~~~~~
test.cpp:5:9: note: template argument deduction/substitution failed:
test.cpp:19:22: note: couldn’t deduce template parameter ‘ResultT’
19 | auto res = timing(my_func, 0.f, 3.f);
| ~~~~~~^~~~~~~~~~~~~~~~~~~
Why cannot g++ deduce the template parameter ResultT
, shouldn't it be given by the function my_func
?
Besides, when I specifically provide the value of ResultT
, it works:
template <typename ResultT, typename FunctionT, typename ...ArgT>
ResultT timing(FunctionT fn, ArgT... args) {
// as before
}
int main() {
auto res = timing<float>(my_func, 0.f, 3.f);
}
Is there a way to compile this without explicitly mentioning the return value of my function? In fact, the function(s) I intend to use this method with do have pretty lengthy type definitions.
Solution
Sure, just use auto
as your return type:
template <typename F, typename ...Args>
auto timing(F&& f, Args&&... args) {
auto result = std::forward<F>(f)(std::forward<Args>(args)...);
return result;
}
If for some reason you feel truly compelled to name the type, you could also do this:
template <typename F, typename ...Args>
std::invoke_result_t<F, Args...> timing(F&& f, Args&&... args) {
std::invoke_result_t<F, Args...> result = std::forward<F>(f)(std::forward<Args>(args)...);
return result;
}
Answered By - Kyle Answer Checked By - Timothy Miller (WPSolving Admin)