我正在用最新的C++技术制作一条类似于装潢器的巨蟒。我已经在这里看到了一些解决方案(Python-like C++ decorators),但我不知道是否可以做得更好。在其他人(Constructing std::function argument from 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,状态lambda,结构函子,函数指针,std::函数
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);这将不是OK - int文本5是不可调用的:
std::function<void(double)> decorated = DurationAssertDecorator(1s, 5);然而,到目前为止,它确实起到了作用:
发布于 2019-02-15 06:32:19
我已经意识到,如果我在调用前和调用后活动中使用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;
});所以我对这个解决方案很满意。
https://stackoverflow.com/questions/54684823
复制相似问题