I have tried to write a lambda that measures the execution time of arbitrary functions. With a lot of help I have managed that for C++14 and functions having a return value, see Measure execution time of arbitrary functions with C++14 lambda.
Then I wanted my code to also work with C++11, therefore I have implemented the same idea with template functions.
Finally I have realized that this code does not work for functions having no return value. It has been quite simple to generalize the template functions to enable time measurement also for functions returning void.
But I am stuck when it comes to the measurement lambda. The compiler complains that the optional return value that I want to use has incomplete type. Is it possible to fix that?
Here is my code:
#include <chrono>
#include <iostream>
#include <set>
#include <boost/config.hpp>
#ifdef BOOST_NO_CXX14_GENERIC_LAMBDAS
/**
* \brief Measures the time of arbitrary function calls.
*
* This template function works with C++11 and therefore it does not use
* universal references.
*
* This is an internal helper template for functions returning void.
*
* \tparam Function function type
* \tparam Parameters parameters type
* \param enabled whether time measurement should be enabled
* \param taskName name for printing the measured time
* \param function function to measure
* \param parameters function arguments
*
* \returns return value from given function
*/
template <typename Function, typename... Parameters>
auto measure(std::true_type, bool enabled,
const std::string& taskName, Function function, Parameters... parameters) ->
decltype(function(parameters...))
{
std::chrono::steady_clock::time_point startTimePoint;
if (enabled)
{
startTimePoint = std::chrono::steady_clock::now();
}
std::forward<decltype(function)>(function)(
std::forward<decltype(parameters)>(parameters)...);
if (enabled)
{
const std::chrono::steady_clock::time_point stopTimePoint =
std::chrono::steady_clock::now();
const std::chrono::duration<double> timeSpan =
std::chrono::duration_cast<std::chrono::duration<double>>(
stopTimePoint - startTimePoint);
std::cout << taskName << " took " << timeSpan.count() << " seconds." <<
std::endl;
}
}
/**
* \brief Measures the time of arbitrary function calls.
*
* This template function works with C++11 and therefore it does not use
* universal references.
*
* This is an internal helper template for functions returning non-void.
*
* \tparam Function function type
* \tparam Parameters parameters type
* \param enabled whether time measurement should be enabled
* \param taskName name for printing the measured time
* \param function function to measure
* \param parameters function arguments
*
* \returns return value from given function
*/
template <typename Function, typename... Parameters>
auto measure(std::false_type, bool enabled,
const std::string& taskName, Function function, Parameters... parameters) ->
decltype(function(parameters...))
{
std::chrono::steady_clock::time_point startTimePoint;
if (enabled)
{
startTimePoint = std::chrono::steady_clock::now();
}
auto returnValue =
std::forward<decltype(function)>(function)(
std::forward<decltype(parameters)>(parameters)...);
if (enabled)
{
const std::chrono::steady_clock::time_point stopTimePoint =
std::chrono::steady_clock::now();
const std::chrono::duration<double> timeSpan =
std::chrono::duration_cast<std::chrono::duration<double>>(
stopTimePoint - startTimePoint);
std::cout << taskName << " took " << timeSpan.count() << " seconds." <<
std::endl;
}
return returnValue;
}
template <typename Function, typename... Parameters>
using ReturnType = typename std::result_of<Function(Parameters...)>::type;
/**
* \brief Measures the time of arbitrary function calls.
*
* This template function works with C++11 and therefore it does not use
* universal references.
*
* \tparam Function function type
* \tparam Parameters parameters type
* \param enabled whether time measurement should be enabled
* \param taskName name for printing the measured time
* \param function function to measure
* \param parameters function arguments
*
* \returns return value from given function
*/
template <typename Function, typename... Parameters>
auto measure(bool enabled, const std::string& taskName, Function function,
Parameters... parameters) -> decltype(function(parameters...))
{
return measure(std::is_void<ReturnType<Function, Parameters...>>{},
enabled, taskName, function, parameters...);
}
#else
/**
* \brief Measures the time of arbitrary function calls.
*
* This lambda works with C++14 and it accepts universal references.
*
* \param enabled whether time measurement should be enabled
* \param taskName name for printing the measured time
* \param function function to measure
* \param parameters function arguments
*
* \returns return value from given function
*/
auto measure = [](bool enabled, const std::string& taskName, auto&& function,
auto&&... parameters) -> decltype(auto)
{
std::chrono::steady_clock::time_point startTimePoint;
if (enabled)
{
startTimePoint = std::chrono::steady_clock::now();
}
decltype(auto) returnValue =
std::forward<decltype(function)>(function)(
std::forward<decltype(parameters)>(parameters)...);
if (enabled)
{
const std::chrono::steady_clock::time_point stopTimePoint =
std::chrono::steady_clock::now();
const std::chrono::duration<double> timeSpan =
std::chrono::duration_cast<std::chrono::duration<double>>(
stopTimePoint - startTimePoint);
std::cout << taskName << " took " << timeSpan.count() << " seconds." <<
std::endl;
}
return returnValue;
};
#endif
int main(int, char**)
{
measure(true, "Populating Ordered Set", []()
{
std::set<int> orderedSet;
for (int i = 0; i < 1000; ++i)
{
orderedSet.insert(i);
}
});
return 0;
}
If it is compiled with a C++11 compiler (like g++ with -std=gnu++11), it uses the template function and therefore works well here. If it is compiled with a C++14 compiler (-std=gnu++14), it uses the lambda and therefore I get this compilation error message:
..\src\Main.cpp: In instantiation of '<lambda(bool, const string&, auto:1&&, auto:2&& ...)> [with auto:1 = main(int, char**)::<lambda()>; auto:2 = {}; std::__cxx11::string = std::__cxx11::basic_string<char>]':
..\src\Main.cpp:186:10: required from here
..\src\Main.cpp:154:24: error: 'void returnValue' has incomplete type
decltype(auto) returnValue =
^~~~~~~~~~~
Thank you very much for any help.