C 17中的Python风格装饰器
Python Style Decorator in C++17
我正在使用最新的C 技术制作python的旅程。我已经在这里看到了一些解决方案(类似Python的C 装饰器),但是我想知道它是否可以做得更好。在其他人的帮助下(构建std ::函数参数来自lambda),我提出了以下解决方案。
template<typename TWrapped>
auto DurationAssertDecorator(const std::chrono::high_resolution_clock::duration& maxDuration, TWrapped&& wrapped)
{
return [wrapped = std::forward<TWrapped>(wrapped), maxDuration](auto&&... args)
{
const auto startTimePoint = std::chrono::high_resolution_clock::now();
static_assert(std::is_invocable<TWrapped, decltype(args)...>::value, "Wrapped object must be invocable");
if constexpr (!(std::is_void<decltype(wrapped(std::forward<decltype(args)>(args)...))>::value))
{
// return by reference will be here not converted to return by value?
//auto result = wrapped(std::forward<decltype(args)>(args)...);
decltype(wrapped(std::forward<decltype(args)>(args)...)) result = wrapped(std::forward<decltype(args)>(args)...);
const auto endTimePoint = std::chrono::high_resolution_clock::now();
const auto callDuration = endTimePoint - startTimePoint;
assert(callDuration <= maxDuration);
return result;
}
else
{
wrapped(std::forward<decltype(args)>(args)...);
const auto endTimePoint = std::chrono::high_resolution_clock::now();
const auto callDuration = endTimePoint - startTimePoint;
assert(callDuration <= maxDuration);
}
};
}
我不是故意使用下面的"自动"来确保返回类型是我期望的(或至少兼容)。
我将能够将其与任何可召唤:无状态lambda,statefull lambda,struct functor,function指针,std :: function
std::function<double(double)> decorated = DurationAssertDecorator(1s, [](const double temperature) { return temperature + 5.0; });
double a = decorated (4);
构图也可以:
std::function<double()> wrapped = LogDecorator(logger, [] { return 4.0; });
std::function<double()> wrapped_wrapped = DurationAssertDecorator(1s, functor);
在 std::function<void(double)> decorated = DurationAssertDecorator(1s, 5);
到目前为止,它可以解决问题,但是:
- 情况 - 包装函数具有返回值 - 我不确定我是否只是通过自动获得结果,并且包装的返回值是参考。如果是这样,则将进行副本,而是保留参考(按指针返回,值得还可以)。这就是为什么我想出那个奇怪的结构。我可以做得更好吗?
- 还有哪些其他改进/修复?
我已经意识到,如果我使用raii对象进行预呼叫活动和后呼叫活动,我可以更简化代码。无需再进行空隙和非空隙返回值处理。
template<typename TWrapped>
auto DurationAssertDecorator(const std::chrono::high_resolution_clock::duration& maxDuration, TWrapped&& wrapped)
{
return [wrapped = std::forward<TWrapped>(wrapped), maxDuration](auto&&... args) mutable
{
static_assert(std::is_invocable<TWrapped, decltype(args)...>::value, "Wrapped object must be invocable");
struct Aspect
{
// Precall logic goes into the constructor
Aspect(const std::chrono::high_resolution_clock::duration& maxDuration)
: _startTimePoint(std::chrono::high_resolution_clock::now())
, _maxDuration(maxDuration)
{}
// Postcall logic goes into the destructor
~Aspect()
{
const auto endTimePoint = std::chrono::high_resolution_clock::now();
const auto callDuration = endTimePoint - _startTimePoint;
assert(callDuration <= _maxDuration);
}
const std::chrono::high_resolution_clock::time_point _startTimePoint;
const std::chrono::high_resolution_clock::duration& _maxDuration;
} aspect(maxDuration);
return wrapped(std::forward<decltype(args)>(args)...);
};
}
它与普通用例一起使用:
auto wrappedFunctor = DurationAssertDecorator(1s, [](const double temperature) { return temperature; });
我也想与非const函子一起使用,例如可变的lambdas:
auto wrappedFunctor = DurationAssertDecorator(1s,
[firstCall = true](const double temperature) mutable
{
if (firstCall)
{
firstCall = false;
return temperature;
}
std::this_thread::sleep_for(2s);
return temperature;
});
所以我对此解决方案感到非常满意。
相关文章:
- Qt VTK交互风格的信号到小部件
- 如何运行位于boost/libs/python/example/tutorial目录中的hello.cpp和Jamfil
- Pybind11:将元组列表从Python传递到C++
- 如何在c++中使用引用实现类似python的行为
- 是否可以通过C++扩展强制多个python进程共享同一内存
- 递归列出所有目录中的C++与Python与Ruby的性能
- IPC使用多个管道和分支进程来运行Python程序
- 从python中调用C++函数并获取返回值
- 我可以使用条件运算符初始化C风格的字符串文字吗
- Visual Studio 2019:插入多个C++风格的单行注释
- Python 3.7 和 excess_args 的 SWIG 问题
- Python中的for循环与C++有何不同
- 如何在本地机器上运行c++和javascript客户端代码(hackerbank风格)
- 使用Pybind11向Python公开Eigen::张量
- Python str to C++ to Python str
- 使用 rangesv3 在 c++ 中模拟 python 风格的列表理解?
- 这种尝试是在C 可靠 /安全的更为Python风格的装饰器中的尝试
- C 17中的Python风格装饰器
- 以numpy/Python的风格访问OpenCV和C++中的矩阵元素
- c++中Python风格的字符串替换