测量任何运行时间的函数,并获取函数返回值

时间:2013-08-14 09:27:56

标签: c++ templates boost void

我有一个类来存储一个函数,当它被调用时它会存储函数的运行时间。 它在void返回类型函数上很好用。但是当我想获得存储函数的返回类型时,我得到了一个'空值不被忽略,因为它应该是'。我无法专门化模板,因为返回类型不是协变的(据我所知)。

所以下面的课很糟糕。

class TimeDurationOperation {
public:
    TimeDurationOperation(boost::function<void(void)> operation_)
        : operation(operation_) { }

    template <typename R> R operate() {
        const boost::posix_time::ptime start =
            boost::posix_time::microsec_clock::local_time();

         R return_value = operation();

        const boost::posix_time::ptime stop =
            boost::posix_time::microsec_clock::local_time();
        elapsed = stop - start;
        return return_value;
    }

    boost::posix_time::time_duration elapsed_time() const {
        return elapsed;
    }

private:
    boost::function<void(void)> operation;
    boost::posix_time::time_duration elapsed;
};

工作版本操作()函数:

void operate() {
    const boost::posix_time::ptime start =
        boost::posix_time::microsec_clock::local_time();

    operation();

    const boost::posix_time::ptime stop =
        boost::posix_time::microsec_clock::local_time();
    elapsed = stop - start;
}

我想这样称呼它:

TimeDurationOperation tdo(boost::bind(detail::fun1, 2000));
tdo.operate();
std::cout << tdo.elapsed_time() << std::endl;

TimeDurationOperation tdo2(boost::bind(detail::fun2, 500));
int r = tdo2.operate<int>();
std::cout << tdo2.elapsed_time() << " and returned: " << r << std::endl;

你的建议是什么?

2 个答案:

答案 0 :(得分:0)

对于类型安全,您将希望TimeDuration知道返回类型。如果它知道参数,它也会更有用:

template<class signature> class TimeDurationOperation;

template<class Ret, class...Params>
class TimeDurationOperation<Ret(Params...) {
public:
    TimeDurationOperation(boost::function<Ret(Params...)> operation_)
        : operation(operation_) { }

    Ret operate(Params... vals) {
        const boost::posix_time::ptime start =
            boost::posix_time::microsec_clock::local_time();

         R return_value = operation(std::forward<Params>(vals)...);

        const boost::posix_time::ptime stop =
            boost::posix_time::microsec_clock::local_time();
        elapsed = stop - start;
        return return_value;
    }

    boost::posix_time::time_duration elapsed_time() const {
        return elapsed;
    }

private:
    boost::function<Ret(Params...)> operation;
    boost::posix_time::time_duration elapsed;
};

现在关于实际问题:模板专业化是第一个也是最明显的事情。

template<class...Params>
class TimeDurationOperation<void(Params...) {
public:
    TimeDurationOperation(boost::function<void(Params...)> operation_)
        : operation(operation_) { }

    void operate(Params... vals) {
        const boost::posix_time::ptime start =
            boost::posix_time::microsec_clock::local_time();

         operation(std::forward<Params>(vals)...);

        const boost::posix_time::ptime stop =
            boost::posix_time::microsec_clock::local_time();
        elapsed = stop - start;
    }

    boost::posix_time::time_duration elapsed_time() const {
        return elapsed;
    }

private:
    boost::function<void(Params...)> operation;
    boost::posix_time::time_duration elapsed;
};

或者,(虽然我认为这是一个可怕的想法),人们可能会滥用析构函数。

    struct RAII_timer {
        RAII_timer(boost::posix_time::time_duration& dest) 
            : start(boost::posix_time::microsec_clock::local_time())
            , elapsed(&dest)
            {}
        RAII_timer(const RAII_timer& NO_COPIES) = delete;
        RAII_timer& operator=(const RAII_timer& NO_COPIES) = delete;
        ~RAII_timer() {
            const boost::posix_time::ptime stop =
                boost::posix_time::microsec_clock::local_time();
            *elapsed = stop - start;
        }

        boost::posix_time::ptime start;
        boost::posix_time::time_duration* elapsed;
    };
    Ret operate(Params... vals) {
        RAII_timer timer(elapsed);
        return operation(std::forward<Params>(vals)...);
    }

答案 1 :(得分:0)

好的,所以这篇文章有点旧,但我认为发布答案会有所帮助。

使用现代C ++(11/14)这项任务非常简单。

#include <chrono>
#include <functional>

template <typename Ret, class... Params>
struct TimeDurationOperation {
    explicit TimeDurationOperation(std::function<Ret(Params...)> operation)
        : operation(operation) { }

    template<class R = Ret>
    typename std::enable_if<!std::is_void<R>::value, R>::type operate(Params... vals) {
        auto start = std::chrono::system_clock::now();
        R return_value(operation(std::forward<Params>(vals)...));
        auto stop = std::chrono::system_clock::now();
        elapsed = stop - start;
        return return_value;
    }

    template<class R = Ret>
    typename std::enable_if<std::is_void<R>::value, void>::type operate(Params... vals) {
        auto start = std::chrono::system_clock::now();
        operation(std::forward<Params>(vals)...);
        auto stop = std::chrono::system_clock::now();
        elapsed = stop - start;
    }

    const std::chrono::duration<double>& elapsed_time() const {
        return elapsed;
    }

private:
    std::function<Ret(Params...)> operation;
    std::chrono::duration<double> elapsed;
};

您可以通过以下方式使用此方法:

int return_test_function(int i) {
    std::this_thread::sleep_for(20ms);
    return i * 2;
}

TimeDurationOperation<int, int> tdo(return_test_function);
auto result = tdo.operate(21);
auto elapsed = static_cast<double>(duration_cast<milliseconds(tdo.elapsed_time()).count());

使用可变参数模板,您可以表示任何参数列表。 使用std :: function,您可以表示任何功能。简单函数(指针)隐式转换为此类型。 使用std :: enable_if进行SFINAE实现。如果enable_if中的表达式为false,则不编译该函数。尝试使用&#34;错误&#34;带模板的函数将导致编译器错误(或警告,具体取决于编译器)。 您可以使用std :: chrono测量已用时间。

注意:此解决方案仅使用标准。不需要第三方库(如Boost)。