尝试构建包装器测量函数调用时间的问题
Problems trying to construct a wrapper measuring function call time
我正在实现一些数据结构,每个数据结构都支持一组命令,例如 INSERT value
。
我使用分词器生成了一个包含每个 word/value.
的向量
我希望能够将 每个 函数调用花费的时间输出到 .txt 文件,加上函数 returned if 它 做 return 某事。
例如,如果命令是INSERT AVLTREE 4
,我只想输出调用avl.insert(4)
所花费的时间。
如果命令是 SEARCH AVLTREE 4
,我想输出调用 avl.search(4)
所花费的时间及其结果(例如 "SUCCESS"
或 "FAILURE"
)。
下面的代码可能有很多问题,但这是我想出的:
我制作了两个文件 (.cpp/.hpp),其中包含以下 self-hacked 函数包装器,以及一个变体和一个结构:
// 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
:
AVL avl;
// stuff
auto out = wrapper(true, avl.insert, 4);
我收到以下错误:
invalid use of non-static member function 'void AVL::insert(int)'
这是一个额外的奖励,它应该提示我我搞砸了但还不能完全理解的地方:
no matching function for call to 'wrapper(bool, <unresolved overloaded function type>, unsigned int&)'
有什么想法吗?
我很感激提前花时间:)
EDIT 1: 问题标题可能不太合适,如果你有好的想法我会愉快地改变
问题出在您 wrapper()
函数使用的极端情况下。让它与成员函数一起工作非常棘手,并且可能与 void
-返回函数一起工作(参见 Jarod42 的优秀 )。这个:
wrapper(true, avl.insert, 4);
由于多种原因将无法编译。不仅avl.insert
无效,即使你试图通过指针传递一个成员函数并传递一个对象来调用它,像这样:
wrapper(true, &AVL::insert, avl, 4);
它仍然无法编译,但现在由于 你如何在 wrapper
.
中调用它
解决方法是使用适合此类工作的工具 - std::invoke
。它正确处理自由函数、成员函数等。示例用法:
#include <iostream>
#include <functional>
struct foo {
void bar(int x) {
std::cout << x;
}
};
template <typename F, typename... Args>
void wrapper(F f, Args&&... args) {
std::invoke(f, std::forward<Args>(args)...);
}
void free_bar() {
std::cout << "free";
}
int main() {
foo f;
wrapper(&foo::bar, f, 1); // pass a pointer to member function and the instance itself, then arguments
wrapper(free_bar);
}
注意代码如何正确处理每种情况。 std::invoke
只是做正确的事。
由于您需要根据 return 类型的不同行为,您可以使用 specialization/SFINAE,例如:
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);});
我正在实现一些数据结构,每个数据结构都支持一组命令,例如 INSERT value
。
我使用分词器生成了一个包含每个 word/value.
的向量我希望能够将 每个 函数调用花费的时间输出到 .txt 文件,加上函数 returned if 它 做 return 某事。
例如,如果命令是INSERT AVLTREE 4
,我只想输出调用avl.insert(4)
所花费的时间。
如果命令是 SEARCH AVLTREE 4
,我想输出调用 avl.search(4)
所花费的时间及其结果(例如 "SUCCESS"
或 "FAILURE"
)。
下面的代码可能有很多问题,但这是我想出的:
我制作了两个文件 (.cpp/.hpp),其中包含以下 self-hacked 函数包装器,以及一个变体和一个结构:
// 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
:
AVL avl;
// stuff
auto out = wrapper(true, avl.insert, 4);
我收到以下错误:
invalid use of non-static member function 'void AVL::insert(int)'
这是一个额外的奖励,它应该提示我我搞砸了但还不能完全理解的地方:
no matching function for call to 'wrapper(bool, <unresolved overloaded function type>, unsigned int&)'
有什么想法吗?
我很感激提前花时间:)
EDIT 1: 问题标题可能不太合适,如果你有好的想法我会愉快地改变
问题出在您 wrapper()
函数使用的极端情况下。让它与成员函数一起工作非常棘手,并且可能与 void
-返回函数一起工作(参见 Jarod42 的优秀
wrapper(true, avl.insert, 4);
由于多种原因将无法编译。不仅avl.insert
无效,即使你试图通过指针传递一个成员函数并传递一个对象来调用它,像这样:
wrapper(true, &AVL::insert, avl, 4);
它仍然无法编译,但现在由于 你如何在 wrapper
.
解决方法是使用适合此类工作的工具 - std::invoke
。它正确处理自由函数、成员函数等。示例用法:
#include <iostream>
#include <functional>
struct foo {
void bar(int x) {
std::cout << x;
}
};
template <typename F, typename... Args>
void wrapper(F f, Args&&... args) {
std::invoke(f, std::forward<Args>(args)...);
}
void free_bar() {
std::cout << "free";
}
int main() {
foo f;
wrapper(&foo::bar, f, 1); // pass a pointer to member function and the instance itself, then arguments
wrapper(free_bar);
}
注意代码如何正确处理每种情况。 std::invoke
只是做正确的事。
由于您需要根据 return 类型的不同行为,您可以使用 specialization/SFINAE,例如:
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);});