尝试构建包装测量函数调用时间的问题 [英] Problems trying to construct a wrapper measuring function call time

查看:28
本文介绍了尝试构建包装测量函数调用时间的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在实现一些数据结构,每个结构都支持一组命令,例如 INSERT value.

I'm implementing some data structures, each supporting a set of commands such as INSERT value.

我使用分词器生成了一个包含每个单词/值的向量.

I've used a tokenizer to generate a vector that holds each word/value.

我希望能够将每个函数调用所花费的时间以及函数返回的如果执行输出到一个.txt文件> 返回一些东西.

I want to be able to output to a .txt file the time every function call took, plus what the function returned if it does return something.

例如,如果命令是INSERT AVLTREE 4,我只想输出调用avl.insert(4)所花费的时间.如果命令是 SEARCH AVLTREE 4,我想输出调用 avl.search(4) 花费的时间,以及它的结果(例如 "SUCCESS""FAILURE").

For example, if the command is INSERT AVLTREE 4, I want to just output the time calling avl.insert(4) took. If the command is SEARCH AVLTREE 4, I want to output the time calling avl.search(4) took, as well as its result (e.g. "SUCCESS" or "FAILURE").

以下代码可能有很多问题,但这是我想出的:

There are probably many things wrong with the following code, but here's what I came up with:

我制作了两个文件 (.cpp/.hpp),其中包含以下自黑客函数包装器,以及一个变体和一个结构:

I made two files (.cpp/.hpp) which contain the following self-hacked function wrapper, and also a variant as well as a struct:

// WRAPPER CPP
// file: wrap.cpp


#include "wrap.hpp"


#include <chrono>
#include <string>
#include <utility>

#include <boost/variant.hpp>


using std::chrono::high_resolution_clock;
using std::chrono::time_point;
using std::chrono::nanoseconds;

using std::string;
using std::to_string;

using std::forward;

using boost::get;
using boost::static_visitor;
using boost::apply_visitor;


// I'm overloading std::to_string, so it works on std::strings as well.
string to_string(const string &value)
{
    return value;
}

// I want to apply to_string on whatever is inside my variant.
class to_string_visitor : public static_visitor<>
{
    public:
        template <typename T>
        void operator()(T & operand) const
        {
            to_string(operand);
        }
};

// Takes two points in time and returns the time 
// between them in nanoseconds.
const nanoseconds::rep duration(const nanoseconds tpoints_difference) noexcept
{
    const auto result = tpoints_difference.count();
    return result;
}

// Generates a point in time.
const high_resolution_clock::time_point timeNow(void) noexcept
{
    const auto result = high_resolution_clock::now();
    return result;
}

// Here's where's the problematic magic happens:
// The ret boolean is set to true if the function F returns a value,
// otherwise, it is set to false.
//
// Variadic arguments are being taken and then std::forwarded to F.
template<typename F, typename... Args>
const output wrapper(bool ret, F function, Args&&... args) noexcept
{
        // Generate a point in time, t1.
    const high_resolution_clock::time_point t1 = timeNow();

        // If F returns a result,
    if (ret == true)
    {
                // assign it to result (my variant).
        result = function(forward<Args>(args)...);
    }
    else
    {
                // just call F with Args forwarded.
        function(forward<Args>(args)...);
    }

        // Generate another point in time, t2 and
        // count the difference between t2 - t1.
    const auto elapsed = duration(timeNow() - t1);

        // Make whatever is inside result a string
        // using std::to_string.
    apply_visitor(to_string_visitor(), result);

        // My struct
    output out;

        // which contains the time elapsed and
        // the result returned
    out.time = elapsed;
    out.result = get<string>(result);

        // I can theoretically use both time elapsed and
        // result returned however I want. Hooray!..almost:(
    return out;
}

这是变体result:

// These are all the types a data structure function may return.
variant<int, unsigned, uint32_t, size_t, graph_size, string> result = 0;

graph_size,仅供参考:

struct graph_size
{
    unsigned vertices; //Number of vertices that the Graph currently contains
    unsigned edges;    //Number of edges that the Graph currently contains
};

最后,output 结构:

typedef struct output
{
    double time;          // function call time
    string result;        // what function returned

        // notice that if function returned nothing,
        // result will be an empty string.
    output() : time(0), result("") {}
} output;

我正在尝试像这样使用 wrapper:

I'm trying to use wrapper like so:

AVL avl;
// stuff
auto out = wrapper(true, avl.insert, 4);

我收到以下错误:

invalid use of non-static member function 'void AVL::insert(int)'

这是一个奖励,它应该提示我我搞砸了但不能完全理解它:

And here's a bonus one which should hint me towards what I botched but just can't quite grasp it:

no matching function for call to 'wrapper(bool, <unresolved overloaded function type>, unsigned int&)'

有什么想法吗?

我感谢所有提前花费的时间:)

I appreciate all time spent in advance :)

EDIT 1: 问题标题可能不太合适,如果你有好的想法,我会很高兴地改变

EDIT 1: The question title may not be very suitable, I'll merrily change if you have something good in mind

推荐答案

由于您需要根据返回类型的不同行为,您可能会使用特殊化/SFINAE,例如:

As you need different behaviour depending of return type, you might use specialization/SFINAE, something like:

template<typename F, typename... Args>
auto wrapper(F function, Args&&... args) noexcept
-> std::enable_if_t<std::is_same<void, std::invoke_result_t<F, Args&&...>>::value, output>
{
    const high_resolution_clock::time_point t1 = timeNow();
    function(forward<Args>(args)...);
    const auto elapsed = duration(timeNow() - t1);

    output out;
    out.time = elapsed;
    out.result = ""; // void return
    return out;
}

template<typename F, typename... Args>
auto wrapper(F function, Args&&... args) noexcept
-> std::enable_if_t<!std::is_same<void, std::invoke_result_t<F, Args&&...>>::value, output>
{
    const high_resolution_clock::time_point t1 = timeNow();
    auto result = function(forward<Args>(args)...);
    const auto elapsed = duration(timeNow() - t1);

    output out;
    out.time = elapsed;
    out.result = to_string(result);
    return out;
}

可能的用法:

AVL avl;

auto out = wrapper([&](){ return avl.insert(4);});

这篇关于尝试构建包装测量函数调用时间的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆