将 c++11 std::function 包装在另一个 std::function 中?
Wrap c++11 std::function in another std::function?
我想将 std::bind() 或 lambda 的结果包装在辅助函数中,以跟踪函数调用的执行时间。我想要一个通用的解决方案,它可以使用任意数量的参数(和 class 方法)并且与 c++11 兼容。
我的意图是获取包装函数并将其传递给 boost::signals2::signal 因此生成的函数对象需要在签名上与原始函数相同。
我基本上是在寻找一些神奇的 class 或函数 Wrapper
,其工作原理如下:
std::function<void(int)> f = [](int x) {
std::cerr << x << std::endl;
};
boost::signals2::signal<void(int)> x_signal;
x_signal.connect(Wrapper<void(int)>(f));
x_signal(42);
这就是打印 42 所花费的时间。
谢谢!
我相信你想做的事情可以用可变模板来解决。
http://www.cplusplus.com/articles/EhvU7k9E/
您基本上可以 "forward" 从外部 std::function 到内部的参数列表。
编辑:
下面,我添加了一个使用可变参数模板概念的最小工作示例。在 main(...)
中,一个 lambda 函数被包装到另一个 std::function
对象中,使用内部 lambda 函数的指定参数。这是通过将要测量的函数作为参数传递给模板函数 measureTimeWrapper
来完成的。它 return 是一个与传入函数具有相同签名的函数(前提是您在 measureTimeWrapper
的模板参数中正确定义了 lambda 的参数列表)。
测量 运行 时间的函数只是坐在这里等待其参数定义的毫秒数。除此之外,它根本不关心时间测量。这是由包装函数完成的。
注意内部函数的return值是这样丢失的;如果你想保留,你可能想改变值的 returned 方式(可能作为一个结构,包含测量时间和 real return 值)它。
记得至少用 -std=c++11
编译你的代码。
#include <iostream>
#include <cstdlib>
#include <functional>
#include <chrono>
#include <thread>
template<typename T, typename... Args>
std::function<double(Args...)> measureTimeWrapper(std::function<T> fncFunctionToMeasure) {
return [fncFunctionToMeasure](Args... args) -> double {
auto tsStart = std::chrono::steady_clock::now();
fncFunctionToMeasure(args...);
auto tsEnd = std::chrono::steady_clock::now();
std::chrono::duration<double> durTimeTaken = tsEnd - tsStart;
return durTimeTaken.count();
};
}
int main(int argc, char** argv) {
std::function<double(int)> fncMeasured = measureTimeWrapper<void(int), int>([](int nParameter) {
std::cout << "Process function running" << std::endl;
std::chrono::milliseconds tsTime(nParameter); // Milliseconds
std::this_thread::sleep_for(tsTime);
});
std::cout << "Time taken: " << fncMeasured(500) << " sec" << std::endl;
return EXIT_SUCCESS;
}
#include <iostream>
#include <functional>
template<typename Signature>
std::function<Signature> Wrapper(std::function<Signature> func)
{
return [func](auto... args)
{
std::cout << "function tracked" << std::endl;
return func(args...);
};
}
int lol(const std::string& str)
{
std::cout << str << std::endl;
return 42;
}
int main(void)
{
auto wrapped = Wrapper<int(const std::string&)>(lol);
std::cout << wrapped("Hello") << std::endl;
}
用您想要的任何跟踪逻辑(计时、缓存等)替换"function tracked"
部分
虽然
这需要c++14
如果是关于性能,我强烈建议不要双重包装函数。
你可以没有那些:
template <typename Caption, typename F>
auto timed(Caption const& task, F&& f) {
return [f=std::forward<F>(f), task](auto&&... args) {
using namespace std::chrono;
struct measure {
high_resolution_clock::time_point start;
Caption const& task;
~measure() { std::cout << " -- (" << task << " completed in " << duration_cast<microseconds>(high_resolution_clock::now() - start).count() << "µs)\n"; }
} timing { high_resolution_clock::now(), task };
return f(std::forward<decltype(args)>(args)...);
};
}
观看现场演示:
#include <chrono>
#include <iostream>
template <typename Caption, typename F>
auto timed(Caption const& task, F&& f) {
return [f=std::forward<F>(f), task](auto&&... args) {
using namespace std::chrono;
struct measure {
high_resolution_clock::time_point start;
Caption const& task;
~measure() { std::cout << " -- (" << task << " completed in " << duration_cast<microseconds>(high_resolution_clock::now() - start).count() << "µs)\n"; }
} timing { high_resolution_clock::now(), task };
return f(std::forward<decltype(args)>(args)...);
};
}
#include <thread>
int main() {
using namespace std;
auto f = timed("IO", [] { cout << "hello world\n"; return 42; });
auto g = timed("Sleep", [](int i) { this_thread::sleep_for(chrono::seconds(i)); });
g(1);
f();
g(2);
std::function<int()> f_wrapped = f;
return f_wrapped();
}
打印(例如):
-- (Sleep completed in 1000188µs)
hello world
-- (IO completed in 2µs)
-- (Sleep completed in 2000126µs)
hello world
-- (IO completed in 1µs)
exitcode: 42
更新:c++11 版本
#include <chrono>
#include <iostream>
namespace detail {
template <typename F>
struct timed_impl {
std::string _caption;
F _f;
timed_impl(std::string const& task, F f)
: _caption(task), _f(std::move(f)) { }
template <typename... Args>
auto operator()(Args&&... args) const -> decltype(_f(std::forward<Args>(args)...))
{
using namespace std::chrono;
struct measure {
high_resolution_clock::time_point start;
std::string const& task;
~measure() { std::cout << " -- (" << task << " completed in " << duration_cast<microseconds>(high_resolution_clock::now() - start).count() << "µs)\n"; }
} timing { high_resolution_clock::now(), _caption };
return _f(std::forward<decltype(args)>(args)...);
}
};
}
template <typename F>
detail::timed_impl<F> timed(std::string const& task, F&& f) {
return { task, std::forward<F>(f) };
}
#include <thread>
int main() {
using namespace std;
auto f = timed("IO", [] { cout << "hello world\n"; return 42; });
auto g = timed("Sleep", [](int i) { this_thread::sleep_for(chrono::seconds(i)); });
g(1);
f();
g(2);
std::function<int()> f_wrapped = f;
return f_wrapped();
}
我想将 std::bind() 或 lambda 的结果包装在辅助函数中,以跟踪函数调用的执行时间。我想要一个通用的解决方案,它可以使用任意数量的参数(和 class 方法)并且与 c++11 兼容。
我的意图是获取包装函数并将其传递给 boost::signals2::signal 因此生成的函数对象需要在签名上与原始函数相同。
我基本上是在寻找一些神奇的 class 或函数 Wrapper
,其工作原理如下:
std::function<void(int)> f = [](int x) {
std::cerr << x << std::endl;
};
boost::signals2::signal<void(int)> x_signal;
x_signal.connect(Wrapper<void(int)>(f));
x_signal(42);
这就是打印 42 所花费的时间。
谢谢!
我相信你想做的事情可以用可变模板来解决。
http://www.cplusplus.com/articles/EhvU7k9E/
您基本上可以 "forward" 从外部 std::function 到内部的参数列表。
编辑:
下面,我添加了一个使用可变参数模板概念的最小工作示例。在 main(...)
中,一个 lambda 函数被包装到另一个 std::function
对象中,使用内部 lambda 函数的指定参数。这是通过将要测量的函数作为参数传递给模板函数 measureTimeWrapper
来完成的。它 return 是一个与传入函数具有相同签名的函数(前提是您在 measureTimeWrapper
的模板参数中正确定义了 lambda 的参数列表)。
测量 运行 时间的函数只是坐在这里等待其参数定义的毫秒数。除此之外,它根本不关心时间测量。这是由包装函数完成的。
注意内部函数的return值是这样丢失的;如果你想保留,你可能想改变值的 returned 方式(可能作为一个结构,包含测量时间和 real return 值)它。
记得至少用 -std=c++11
编译你的代码。
#include <iostream>
#include <cstdlib>
#include <functional>
#include <chrono>
#include <thread>
template<typename T, typename... Args>
std::function<double(Args...)> measureTimeWrapper(std::function<T> fncFunctionToMeasure) {
return [fncFunctionToMeasure](Args... args) -> double {
auto tsStart = std::chrono::steady_clock::now();
fncFunctionToMeasure(args...);
auto tsEnd = std::chrono::steady_clock::now();
std::chrono::duration<double> durTimeTaken = tsEnd - tsStart;
return durTimeTaken.count();
};
}
int main(int argc, char** argv) {
std::function<double(int)> fncMeasured = measureTimeWrapper<void(int), int>([](int nParameter) {
std::cout << "Process function running" << std::endl;
std::chrono::milliseconds tsTime(nParameter); // Milliseconds
std::this_thread::sleep_for(tsTime);
});
std::cout << "Time taken: " << fncMeasured(500) << " sec" << std::endl;
return EXIT_SUCCESS;
}
#include <iostream>
#include <functional>
template<typename Signature>
std::function<Signature> Wrapper(std::function<Signature> func)
{
return [func](auto... args)
{
std::cout << "function tracked" << std::endl;
return func(args...);
};
}
int lol(const std::string& str)
{
std::cout << str << std::endl;
return 42;
}
int main(void)
{
auto wrapped = Wrapper<int(const std::string&)>(lol);
std::cout << wrapped("Hello") << std::endl;
}
用您想要的任何跟踪逻辑(计时、缓存等)替换"function tracked"
部分
虽然
这需要c++14
如果是关于性能,我强烈建议不要双重包装函数。
你可以没有那些:
template <typename Caption, typename F>
auto timed(Caption const& task, F&& f) {
return [f=std::forward<F>(f), task](auto&&... args) {
using namespace std::chrono;
struct measure {
high_resolution_clock::time_point start;
Caption const& task;
~measure() { std::cout << " -- (" << task << " completed in " << duration_cast<microseconds>(high_resolution_clock::now() - start).count() << "µs)\n"; }
} timing { high_resolution_clock::now(), task };
return f(std::forward<decltype(args)>(args)...);
};
}
观看现场演示:
#include <chrono>
#include <iostream>
template <typename Caption, typename F>
auto timed(Caption const& task, F&& f) {
return [f=std::forward<F>(f), task](auto&&... args) {
using namespace std::chrono;
struct measure {
high_resolution_clock::time_point start;
Caption const& task;
~measure() { std::cout << " -- (" << task << " completed in " << duration_cast<microseconds>(high_resolution_clock::now() - start).count() << "µs)\n"; }
} timing { high_resolution_clock::now(), task };
return f(std::forward<decltype(args)>(args)...);
};
}
#include <thread>
int main() {
using namespace std;
auto f = timed("IO", [] { cout << "hello world\n"; return 42; });
auto g = timed("Sleep", [](int i) { this_thread::sleep_for(chrono::seconds(i)); });
g(1);
f();
g(2);
std::function<int()> f_wrapped = f;
return f_wrapped();
}
打印(例如):
-- (Sleep completed in 1000188µs)
hello world
-- (IO completed in 2µs)
-- (Sleep completed in 2000126µs)
hello world
-- (IO completed in 1µs)
exitcode: 42
更新:c++11 版本
#include <chrono>
#include <iostream>
namespace detail {
template <typename F>
struct timed_impl {
std::string _caption;
F _f;
timed_impl(std::string const& task, F f)
: _caption(task), _f(std::move(f)) { }
template <typename... Args>
auto operator()(Args&&... args) const -> decltype(_f(std::forward<Args>(args)...))
{
using namespace std::chrono;
struct measure {
high_resolution_clock::time_point start;
std::string const& task;
~measure() { std::cout << " -- (" << task << " completed in " << duration_cast<microseconds>(high_resolution_clock::now() - start).count() << "µs)\n"; }
} timing { high_resolution_clock::now(), _caption };
return _f(std::forward<decltype(args)>(args)...);
}
};
}
template <typename F>
detail::timed_impl<F> timed(std::string const& task, F&& f) {
return { task, std::forward<F>(f) };
}
#include <thread>
int main() {
using namespace std;
auto f = timed("IO", [] { cout << "hello world\n"; return 42; });
auto g = timed("Sleep", [](int i) { this_thread::sleep_for(chrono::seconds(i)); });
g(1);
f();
g(2);
std::function<int()> f_wrapped = f;
return f_wrapped();
}