I'm going to make a benchmark function, which measures the elapsed time of given function execution and returns execution result and elapsed time.
template <typename TResult>
struct BenchmarkResult{
TResult result;
const long elapsed;
};
template <typename Ratio, typename TResult, typename... TParams>
BenchmarkResult<TResult> benchmark(TResult (*function)(TParams...), TParams ...params){
using namespace std::chrono;
const auto begin = high_resolution_clock::now();
auto result = function(std::forward<TParams>(params)...);
const auto end = high_resolution_clock::now();
return { std::move(result), duration_cast<Ratio>(end - begin).count() };
}
And for example,
int sleep(int seconds){
using namespace std::chrono_literals;
std::this_thread::sleep_for(1s);
return seconds * 1e6; // return the given second in microsecond unit
}
// (implement above code)
int main(){
auto [elapsed_us, elapsed_ms] = benchmark<std::chrono::milliseconds>(sleep, 1);
std::cout << "Elapsed ms: " << elapsed_ms << " Elapsed us: " << elapsed_us;;
return 0;
}
Will output like
Elapsed ms: 1005 Elapsed us: 1000000
My goal is to change the argument type like BenchmarkResult<TResult> benchmark(std::function<TResult(TParams...)> function, TParams ...params). But it does not works for the above example in the latest C++ version.
The compiler says,
/main.cpp: In function 'int main()':
/main.cpp:76:73: error: no matching function for call to 'benchmark<std::chrono::milliseconds>(int (&)(int), int)'
76 | auto [elapsed_us, elapsed_ms] = benchmark<std::chrono::milliseconds>(sleep, 1);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~
/main.cpp:54:26: note: candidate: 'template<class Ratio, class TResult, class ... TParams> BenchmarkResult<TResult> benchmark(std::function<TResult(TParams ...)>, TParams ...)'
54 | BenchmarkResult<TResult> benchmark(std::function<TResult(TParams...)> function, TParams ...params){ // TODO: use std::function instead of function pointer
| ^~~~~~~~~
/main.cpp:54:26: note: template argument deduction/substitution failed:
/main.cpp:76:73: note: mismatched types 'std::function<TResult(TParams ...)>' and 'int (*)(int)'
76 | auto [elapsed_us, elapsed_ms] = benchmark<std::chrono::milliseconds>(sleep, 1);
How can I achieve this?
Related
I try to implement a class which accepts a function and a variadic argument list as input to execute these functions later on a worker thread. My current implementation has a problem, if one of the arguments is a reference.
Have a look at the following smaller code example:
#include <functional>
#include <iostream>
template<typename Result, typename ...Args>
Result Foo(Result f(Args...), Args... args)
{
return f(args...);
}
int BarValue(int x){return x;}
int BarPointer(int* x){ *x++;return *x; }
int BarRef(int& x){ x++; return x; }
int main()
{
int x{0};
std::cout << Foo(BarValue, x) << std::endl;
std::cout << Foo(BarPointer, &x) << std::endl;
std::cout << Foo(BarRef, x) << std::endl; // does not compile: Error 1
std::cout << Foo(BarRef, std::ref(x)) << std::endl; // does also not compile: Error 2
return 0;
}
Error 1:
<source>: In function 'int main()':
<source>:31:31: error: no matching function for call to 'Foo(int (&)(int&), int&)'
31 | std::cout << Foo(BarRef, x) << std::endl;
| ^
<source>:4:8: note: candidate: 'template<class Result, class ... Args> Result Foo(Result (*)(Args ...), Args ...)'
4 | Result Foo(Result f(Args...), Args... args)
| ^~~
<source>:4:8: note: template argument deduction/substitution failed:
<source>:31:31: note: inconsistent parameter pack deduction with 'int&' and 'int'
31 | std::cout << Foo(BarRef, x) << std::endl;
| ^
ASM generation compiler returned: 1
<source>: In function 'int main()':
<source>:31:31: error: no matching function for call to 'Foo(int (&)(int&), int&)'
31 | std::cout << Foo(BarRef, x) << std::endl;
| ^
<source>:4:8: note: candidate: 'template<class Result, class ... Args> Result Foo(Result (*)(Args ...), Args ...)'
4 | Result Foo(Result f(Args...), Args... args)
| ^~~
<source>:4:8: note: template argument deduction/substitution failed:
<source>:31:31: note: inconsistent parameter pack deduction with 'int&' and 'int'
31 | std::cout << Foo(BarRef, x) << std::endl;
|
^
Error 2:
<source>: In function 'int main()':
<source>:33:41: error: no matching function for call to 'Foo(int (&)(int&), std::reference_wrapper<int>)'
33 | std::cout << Foo(BarRef, std::ref(x)) << std::endl;
| ^
<source>:5:8: note: candidate: 'template<class Result, class ... Args> Result Foo(Result (*)(Args ...), Args ...)'
5 | Result Foo(Result f(Args...), Args... args)
| ^~~
<source>:5:8: note: template argument deduction/substitution failed:
<source>:33:41: note: inconsistent parameter pack deduction with 'int&' and 'std::reference_wrapper<int>'
33 | std::cout << Foo(BarRef, std::ref(x)) << std::endl;
| ^
ASM generation compiler returned: 1
<source>: In function 'int main()':
<source>:33:41: error: no matching function for call to 'Foo(int (&)(int&), std::reference_wrapper<int>)'
33 | std::cout << Foo(BarRef, std::ref(x)) << std::endl;
| ^
<source>:5:8: note: candidate: 'template<class Result, class ... Args> Result Foo(Result (*)(Args ...), Args ...)'
5 | Result Foo(Result f(Args...), Args... args)
| ^~~
<source>:5:8: note: template argument deduction/substitution failed:
<source>:33:41: note: inconsistent parameter pack deduction with 'int&' and 'std::reference_wrapper<int>'
33 | std::cout << Foo(BarRef, std::ref(x)) << std::endl;
| ^
Execution build compiler returned: 1
Compiled with gcc 10.2 and -O3 -std=c++17 : GodBolt
How can I solve this reference problem?
My recommendation is that you take a look at how the standard library itself uses templates to pass callable objects (functions, lambdas, etc.): By using a single template type:
template<typename Func, typename ...Args>
auto Foo(Func f, Args&&... args)
{
return f(std::forward<Args>(args)...);
}
Note that I have added a call to std::forward to properly "forward" the arguments.
Also note that I made the return-type auto to let the compiler deduce the return type.
If I understand your comments correctly, you want to create a variable that holds the returned value of f, and then return that variable later? Then you could either do it using decltype as you do in your compiler-explorer link, or just use plain auto again when defining and initializing your variable:
template<typename Func, typename ...Args>
auto Foo(Func f, Args&&... args)
{
auto value = f(std::forward<Args>(args)...);
// Do something with the variable value...
return value;
}
This will of course not work if the function f have a void return value.
I have written a generic exponential backoff retry loop in C++11. I'm using std::function to pass the callable to retry loop. callable will be retried if isRetriable function returns true.
#include <algorithm>
#include <cassert>
#include <chrono>
#include <functional>
#include <iostream>
#include <thread>
constexpr int64_t max_backoff_milliseconds = 30000; // 30 seconds
template <class R, class... Args>
R Retry(int max_retry_count, int64_t initial_dealy_milliseconds,
const std::function<bool(R)> &isRetriable,
const std::function<R(Args...)> &callable, Args &&... args)
{
int retry_count = 0;
while (true) {
auto status = callable(std::forward<Args>(args)...);
if (!IsRetriable(status)) {
return status;
}
if (retry_count >= max_retry_count) {
// Return status and abort retry
return status;
}
int64_t delay_milliseconds = 0;
if (initial_dealy_milliseconds > 0) {
delay_milliseconds =
std::min(initial_dealy_milliseconds << retry_count,
max_backoff_milliseconds);
}
std::cout << "Callable execution failed. Retry Count:"
<< retry_count + 1 << std::endl;
std::this_thread::sleep_for(
std::chrono::milliseconds(delay_milliseconds));
retry_count++;
}
}
bool isRetriable(int status) {
if (status == 5)
return true;
return false;
}
int foo(int x, int y) {
static int a = 1;
a += (x + y);
return a / 6;
}
int main() {
auto result = Retry(1000, 100, isRetriable, foo, 1, 3);
std::cout << result << std::endl;
return 0;
}
When I compile it, I'm getting below error:
prog.cpp: In function ‘int main()’:
prog.cpp:50:71: error: no matching function for call to ‘Retry(int,
int, bool (&)(int), int (&)(int, int), int, int)’
auto result = Retry<int, int, int>(1000, 100, isRetriable, foo, 1, 3);
^
prog.cpp:11:3: note: candidate: template<class R, class ... Args> R
Retry(int, int64_t, const std::function<bool(R)>&, const
std::function<_Res(_ArgTypes ...)>&, Args&& ...)
R Retry(int max_retry_count,
^~~~~
prog.cpp:11:3: note: template argument deduction/substitution failed:
prog.cpp:50:71: note: mismatched types ‘const
std::function<int(_ArgTypes ...)>’ and ‘int(int, int)’
auto result = Retry<int, int, int>(1000, 100, isRetriable, foo, 1, 3);
^
Could someone explain to me why I have this error?
I'm sure there's a good duplicate for this but...
Here's a shorter reproduction:
template <typename T> void foo(std::function<bool(T)> ) { }
bool maybe(int ) { return false; }
foo(maybe); // error: no matching function call to 'foo(bool (&)(int))'
You may ask - what?! maybe is something that's callable with some T that returns bool. But that's not how template deduction works. In order to deduce std::function<bool(T)> against an argument, that argument needs to be a std::function. maybe isn't a std::function, it's just a function, so that deduction fails. Any kind of deduction with a different kind of expression will also fail:
foo([](int ) { return true; }); // also error
Basically, trying to deduce a std::function is almost always the wrong thing to do. First, it's wrong because it won't work. Second, it's wrong because even if it did work, you're incurring type erasure in a context in which you probably don't need it.
What you want to do instead is deduce arbitrary callables, and then determine what these other arguments are based on those callables. The return type of callable is just what you get when you call callable with Args..., and you want to ensure that isRetriable is a predicate on that type.
One approach to that is:
template <typename Predicate, typename Callable, typename... Args,
// figure out what the callable returns
typename R = std::decay_t<std::invoke_result_t<Callable&, Args...>>,
// require that Predicate is actually a Predicate
std::enable_if_t<
std::is_convertible_v<std::invoke_result_t<Predicate&, R>, bool>,
int> = 0>
R Retry(int max_retry_count, int64_t initial_dealy_milliseconds,
Predicate&& isRetriable,
Callable&& callable,
Args&&... args)
{
// ....
}
While writing some template code, I ran into <unresolved overloaded function type> errors which can be reduced to the following.
template <int N>
auto bar()
{
return N;
}
int main(int, char* [])
{
auto foo = [] (auto func) {
return func();
};
foo(bar<3>);
}
With the errors being:
unresolved_overload.cpp: In function 'int main(int, char**)':
unresolved_overload.cpp:26:28: error: no match for call to '(main(int, char**)::<lambda(auto:1)>) (<unresolved overloaded function type>)'
std::cout << foo(bar<3>) << std::endl;
^
unresolved_overload.cpp:21:29: note: candidate: template<class auto:1> constexpr main(int, char**)::<lambda(auto:1)>::operator decltype (((const main(int, char**)::<lambda(auto:1)>*)((const main(int, char**)::<lambda(auto:1)>* const)0))->operator()(static_cast<auto:1&&>(<anonymous>))) (*)(auto:1)() const
auto foo = [] (auto func) {
^
unresolved_overload.cpp:21:29: note: template argument deduction/substitution failed:
unresolved_overload.cpp:26:28: note: couldn't deduce template parameter 'auto:1'
std::cout << foo(bar<3>) << std::endl;
^
unresolved_overload.cpp:21:29: note: candidate: template<class auto:1> main(int, char**)::<lambda(auto:1)>
auto foo = [] (auto func) {
^
unresolved_overload.cpp:21:29: note: template argument deduction/substitution failed:
unresolved_overload.cpp:26:28: note: couldn't deduce template parameter 'auto:1'
std::cout << foo(bar<3>) << std::endl;
If we replace the auto-return with the explicit return type, int, the example will compile fine.
Why does auto-return run into these issues? I looked into template argument deduction and substitution but the search was largely unfruitful. I thought it might have something to do with the order of template instantiation / etc but couldn't make too much sense of it...
Per AndyG's suggestion, I found the same issue on GCC's bug list. Bug 64194. First reported in 2014. Thus the conclusion seems to be that this is a GCC bug and thankfully not another special case for templates.
Working around this just requires having something else to trigger the instantiation (e.g. assign to a variable, a using declaration).
Try this:
template <typename func>
auto bar(func&& f)->decltype(f())
{
return f();
}
int main()
{
int i = 100;
auto f = [=]()
{
return i;
};
bar(f);
return 0;
}
I am trying to calculate a chrono duration from two chrono time_points like so
#include <chrono>
using namespace std;
using namespace std::chrono;
int main() {
time_point<high_resolution_clock> start = high_resolution_clock::now();
time_point<high_resolution_clock> end = high_resolution_clock::now();
duration<milli> difference = duration_cast<milli>(end - start);
return 0;
}
http://ideone.com/wUKb9S
I am totally puzzled by the compiler error messages:
Compilation error time: 0 memory: 0 signal:0
prog.cpp: In function 'int main()':
prog.cpp:9:63: error: no matching function for call to 'duration_cast(std::__success_type<std::chrono::duration<long long int, std::ratio<1ll, 1000000000ll> > >::type)'
duration<milli> difference = duration_cast<milli>(end - start);
^
prog.cpp:9:63: note: candidate is:
In file included from prog.cpp:2:0:
/usr/include/c++/4.9/chrono:194:7: note: template<class _ToDur, class _Rep, class _Period> constexpr typename std::enable_if<std::chrono::__is_duration<_Tp>::value, _ToDur>::type std::chrono::duration_cast(const std::chrono::duration<_Rep, _Period>&)
duration_cast(const duration<_Rep, _Period>& __d)
^
/usr/include/c++/4.9/chrono:194:7: note: template argument deduction/substitution failed:
/usr/include/c++/4.9/chrono: In substitution of 'template<class _ToDur, class _Rep, class _Period> constexpr typename std::enable_if<std::chrono::__is_duration<_Tp>::value, _ToDur>::type std::chrono::duration_cast(const std::chrono::duration<_Rep, _Period>&) [with _ToDur = std::ratio<1ll, 1000ll>; _Rep = <missing>; _Period = <missing>]':
prog.cpp:9:63: required from here
/usr/include/c++/4.9/chrono:194:7: error: no type named 'type' in 'struct std::enable_if<false, std::ratio<1ll, 1000ll> >'
Is the difference between two time_points not a duration? Can I not convert between duration types to get a millisecond duration representation?
milli is an typedef for std::ratio<1, 1000> which is not a valid representation for a duration, it should be something like duration<long, milli>, or simply std::chrono::milliseconds
auto difference = duration_cast<milliseconds>(end - start);
I have been reading up on, how to perform a std::bind on a regular function.
And store the free function or member function into a std::function.
However, if I try to use a placeholder for one argument and an actual value for the other argument; I am not able to make a call(causes compilation error) to the std::function
So I tried the following code:
#include <random>
#include <iostream>
#include <memory>
#include <functional>
int g(int n1, int n2)
{
return n1+n2;
}
int main()
{
using namespace std::placeholders; // for _1, _2, _3...
std::function<int(int,int)> f3 = std::bind(&g, std::placeholders::_1, 4);
std::cout << f3(1) << '\n';
//this works just fine
auto f4 = std::bind(&g, std::placeholders::_1, 4);
std::cout << f4(1) << '\n';
}
I get the following error g++ 4.7
prog.cpp: In function 'int main()':
prog.cpp:17:22: error: no match for call to '(std::function<int(int, int)>) (int)'
std::cout << f3(1) << '\n';
^
In file included from /usr/include/c++/4.9/memory:79:0,
from prog.cpp:3:
/usr/include/c++/4.9/functional:2142:11: note: candidate is:
class function<_Res(_ArgTypes...)>
^
/usr/include/c++/4.9/functional:2434:5: note: _Res std::function<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) const [with _Res = int; _ArgTypes = {int, int}]
function<_Res(_ArgTypes...)>::
^
/usr/include/c++/4.9/functional:2434:5: note: candidate expects 2 arguments, 1 provided
If you're binding an argument to the function int g(int, int), what remains as a callable is a function taking one int as an argument, not two.
Try this:
std::function<int(int)> f3 = std::bind(&g, std::placeholders::_1, 4);
the type of your std::function should be:
std::function<int(int)> f3 = std::bind(&g, std::placeholders::_1, 4);
~~~
one argument
Your bind creates a function with one parameter. That's why you call f3 as this:
std::cout << f3(1) << '\n';
note: candidate expects 2 arguments, 1 provided
should have been your clue