I have the following api:
old_operation(stream, format, varArgs);
我希望您能够写一个适配器,使得以下调用方式成为可能:
stream << operation(format, varArgs);
为实现此目的,我使用了一个临时对象,存储对varArgs的引用,并重载了
operator<<
,以应用old_operation()
,代码如下:template<typename ...T>
decltype(auto) storage(T&& ...t) {
return [&](auto&& f) ->decltype(auto) {
return std::forward<decltype(f)>(f)(t...);
};
}
template<typename ...T>
class Operation
{
using Storage = decltype(storage(std::declval<T>()...));
public:
template<typename ...Args>
explicit Operation(Args&& ...args) :
mArgs(storage(std::forward<Args>(args)...)) {};
template<class StreamType>
StreamType& Apply(StreamType& stream)
{
auto f = [&](auto&& ...xs)
{
old_operation(stream, std::forward<decltype(xs)>(xs)...);
}
mArgs(f);
return stream;
}
private:
Storage mArgs;
};
template<typename ...Args>
Operation<Args...> MakeOperation(Args&&... args)
{
return Operation<Args...>(std::forward<Args>(args)...);
}
template<class StreamType, typename ...Args>
StreamType& operator<<(StreamType& stream, Operation<Args...>&& operation)
{
return operation.Apply(stream);
}
这很好,但现在我需要在操作调用中添加一些
using namespace
声明:假设我有:
namespace X {namespace Y { namespace Z { int formater(double x) { return std::round(x); }}}
我不想为这个调用添加所有命名空间,所以我正在做类似于以下的事情:
#define OPERATION(...) \
[&]() { \
using namespace ::X:Y:Z; \
return Operation("" __VA_ARGS__); }() \
这让我可以做到:
stream << OPERATION(format, formater(2.3));
lambda表达式的问题在于临时变量被创建在不同的作用域中,而Apply()
调用却在另一个作用域中,这是未定义行为。我不知道是否通过将const限定符添加到mArgs中可以延长捕获引用的生命周期,如此处所述。 我不确定是否适用,我假设它们是基于堆栈的引用,并且通过将const限定符添加到mArgs中,该限定符将应用于捕获的引用。
const &
延长临时变量的生命周期只适用于本地函数变量。您不能将临时变量传递给类,然后使用const &
持有它。 - NathanOlivertemplate <typename Stream, typename Format, typename... Rest> Stream& operator<<(Stream& strm, Format&& f, Rest&&... vargs) { old_operation(stm, std::forward<Format>(f), std::forward<Rest>(vargs)...); return strm; }
这样简单的东西对你来说不能工作?只是出于好奇问一下。 - Arunmu