C+中的Python风格装饰器+;17 我正在用最新的C++技术制作一个Python风格的装饰器。我已经在这里看到了一些解决方案(),但我想知道是否可以做得更好。在别人的帮助下()我想出了以下解决方案 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); } }; } 模板 自动DurationAssertDecorator(常数标准::时钟::高分辨率时钟::duration&maxDuration,TWrapped&wrapped) { 返回[wrapped=std::forward(wrapped),maxDuration](自动参数) { const auto startTimePoint=std::chrono::高分辨率时钟::now(); 静态_断言(std::is_invocable::value,“包装的对象必须是invocable”); 如果constexpr(!(std::is_void::value)) { //按引用返回是否在此处转换为按值返回? //自动结果=包装(标准::转发(参数)…); decltype(wrapped(std::forward(args)…)结果=wrapped(std::forward(args)…); const auto endTimePoint=std::chrono::high_resolution_clock::now(); const auto callDuration=endTimePoint-startTimePoint; assert(callDuration
我已经意识到,如果我在调用前和调用后活动中使用RAII对象,我可以大大简化代码。不再需要处理void和non-void返回值C+中的Python风格装饰器+;17 我正在用最新的C++技术制作一个Python风格的装饰器。我已经在这里看到了一些解决方案(),但我想知道是否可以做得更好。在别人的帮助下()我想出了以下解决方案 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); } }; } 模板 自动DurationAssertDecorator(常数标准::时钟::高分辨率时钟::duration&maxDuration,TWrapped&wrapped) { 返回[wrapped=std::forward(wrapped),maxDuration](自动参数) { const auto startTimePoint=std::chrono::高分辨率时钟::now(); 静态_断言(std::is_invocable::value,“包装的对象必须是invocable”); 如果constexpr(!(std::is_void::value)) { //按引用返回是否在此处转换为按值返回? //自动结果=包装(标准::转发(参数)…); decltype(wrapped(std::forward(args)…)结果=wrapped(std::forward(args)…); const auto endTimePoint=std::chrono::high_resolution_clock::now(); const auto callDuration=endTimePoint-startTimePoint; assert(callDuration,c++,lambda,stl,c++17,C++,Lambda,Stl,C++17,我已经意识到,如果我在调用前和调用后活动中使用RAII对象,我可以大大简化代码。不再需要处理void和non-void返回值 template<typename TWrapped> auto DurationAssertDecorator(const std::chrono::high_resolution_clock::duration& maxDuration, TWrapped&& wrapped) { return [wrapped = std
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)...);
};
}
我还想使用非常量函子,比如可变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;
});
所以我对这个解决方案很满意。你确定要从lambda capture中的
包装
移动吗?似乎std::forward
可能是一个更好的方法。谢谢,我认为你是对的:forward将与正常和移动引用一起工作。我已经在问题中修改了代码
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);
}
};
}
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; });
auto wrappedFunctor = DurationAssertDecorator(1s,
[firstCall = true](const double temperature) mutable
{
if (firstCall)
{
firstCall = false;
return temperature;
}
std::this_thread::sleep_for(2s);
return temperature;
});