2

我有一个类来存储一个函数,当它被调用时,它会存储函数的运行时间。它对 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;

你有什么建议?

4

2 回答 2

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)...);
    }
于 2014-07-21T22:27:44.803 回答
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,则不编译该函数。尝试对模板使用“错误”函数将导致编译器错误(或警告,取决于编译器)。您可以使用 std::chrono 测量经过的时间。

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

于 2017-08-15T11:01:24.390 回答