1

I am trying to implement a generic function which records how long another function took to run.

#include <iostream>
#include <future>
#include <thread>
#include <vector>
#include <functional>
#include <numeric>
#include <memory>

template<typename Res, typename Func, typename...Args>
std::pair<Res, double> ftime(Func fun, Args&&... args)
{
  auto start = std::chrono::system_clock::now();
  Res res = fun(std::forward<Args>(args)...);
  std::chrono::duration<double> duration = std::chrono::system_clock::now() - start;
  return std::make_pair(res, duration.count());
}

int main ()
{
  std::vector<int> values (100, 1);

  auto res = ftime(std::accumulate, values.begin(), values.end(), 0);
  std::cout << "Sum up " << values.size() << std::endl;
  std::cout << "Serial sum =  " <<  res.first << " took :  " << res.second << std::endl;
}

The above code fails to compile with the following error:

sum_1000000.cpp: In function ‘int main()’:
sum_1000000.cpp:22:68: error: no matching function for call to ‘ftime(<unresolved overloaded function type>, std::vector<int>::iterator, std::vector<int>::iterator, int)’
   auto res = ftime(std::accumulate, values.begin(), values.end(), 0);
                                                                    ^
sum_1000000.cpp:10:24: note: candidate: template<class Res, class Func, class ... Args> std::pair<Res, double> ftime(Func, Args&& ...)
 std::pair<Res, double> ftime(Func fun, Args&&... args)
                        ^
sum_1000000.cpp:10:24: note:   template argument deduction/substitution failed:
sum_1000000.cpp:22:68: note:   couldn't deduce template parameter ‘Res’
   auto res = ftime(std::accumulate, values.begin(), values.end(), 0);

As far I've understood, the compiler cannot indentify the template types of the std::acumulate function. What am I doing wrong?

Thank you

Giuseppe Pes
  • 7,772
  • 3
  • 52
  • 90

2 Answers2

2

There are a couple of issues in the code.

Deduce the function return type first:

template<typename Func, typename...Args>
auto ftime(Func fun, Args&&... args) -> std::pair<decltype(fun(std::forward<Args>(args)...)), double>
{
  auto start = std::chrono::system_clock::now();
  auto res = fun(std::forward<Args>(args)...);
  std::chrono::duration<double> duration = std::chrono::system_clock::now() - start;
  return std::make_pair(res, duration.count());
}

std::accumulate is not a function, rather a template. The easiest is to wrap the call into a lambda:

auto res = ftime([&values]() { return std::accumulate(values.begin(), values.end(), 0); });
Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
1

The compiler cannot deduce Res of your template as well as it cannot deduce the template paramters for accumulate.

#include <utility>
#include <chrono>
#include <vector>
#include <numeric>
#include <iostream>

template<typename Func, typename...Args>
auto invoke_timed(Func&& fun, Args&&... args) -> 
  std::pair<decltype(std::forward<Func>(fun)(std::forward<Args>(args)...)), 
  std::chrono::system_clock::duration::rep>
{
  auto start = std::chrono::system_clock::now();
  auto res = std::forward<Func>(fun)(std::forward<Args>(args)...);
  return std::make_pair(res, (std::chrono::system_clock::now() - start).count());
}

int main()
{
  std::vector<int> values(100, 1);
  auto res = invoke_timed(std::accumulate<std::vector<int>::iterator, int>, 
    values.begin(), values.end(), 0);

  std::cout << res.first << ", " << res.second << "\n";
  return 0;
}
Pixelchemist
  • 24,090
  • 7
  • 47
  • 71
  • why are u using a right reference for `Func` ? – Giuseppe Pes Sep 08 '16 at 14:13
  • @GiuseppePes: There is no right/rvalue reference but a forwarding reference and I use it to preserve the value category of the passed function object in order to avoid copies since the parameter would allow big function objects which would be copied the way you wrote it. – Pixelchemist Sep 08 '16 at 18:51
  • I see. Aren t forwarding reference and evaluate reference the same thing? – Giuseppe Pes Sep 08 '16 at 18:59
  • @GiuseppePes: No, forwarding references (or universal references) aren't rvalue references. See: [Universal references in C++ - Scott Meyers](https://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers). – Pixelchemist Sep 08 '16 at 20:29