我会避免直接翻译 Java 代码。
一种 C++ 方式是拥抱价值观。
template<class Sig>
struct adapter;
template<class Out, class In>
struct adapter<Out(In)>:std::function<Out(In)>
{
using std::function<Out(In)>::function;
template<class Next, class Result=std::invoke_result_t<Next const&, Out>>
adapter<Result(In)> chain( Next next ) const& {
auto tmp=*this;
return std::move(tmp).chain(std::move(next));
}
template<class Next, class Result=std::invoke_result_t<Next, Out>>
adapter<Result(In)> chain( Next next ) && {
return [self=std::move(*this), next=std::move(next)](In in)->Result {
return next(self(std::forward<In>(in)));
};
}
};
我们去。
adapter<int(double)> rounder=[](double d){return std::floor(d);};
adapter<double(std::istream&)> double_reader=[](auto&is){double d; is>>d; return d;};
adapter<int(std::istream&)> int_reader=double_reader.chain(rounder);
std::cout << int_reader(std::cin);
等等
这些适配器是多态值类型。您可以将它们与函数指针、lambda、std 函数或其他函数对象链接起来
x.adapt(foo) 调用在上面的代码中拼写为x(foo)。主要目的是被调用的对象......可以使用operator() 使 then 可调用。
Live example.
设计:
我让std::function 完成了大部分繁重的工作。它是一种支持调用和可空性的多态值类型。
我们只是从它继承,转发构造函数,并添加一个检查兼容性并推断返回类型的.chain 方法。
我们可以扩展适配器以轻松支持多合一适配。第一步是支持多个输入,只需在正确的位置添加一堆...s:
template<class Sig>
struct adapter;
template<class Out, class... In>
struct adapter<Out(In...)>:std::function<Out(In...)>
{
using std::function<Out(In...)>::function;
template<class Next, class Result=std::invoke_result_t<Next const&, Out>>
adapter<Result(In...)> chain( Next next ) const& {
auto tmp=*this;
return std::move(tmp).chain(std::move(next));
}
template<class Next, class Result=std::invoke_result_t<Next, Out>>
adapter<Result(In...)> chain( Next next ) && {
return [self=std::move(*this), next=std::move(next)](In... in)->Result {
return next(self(std::forward<In>(in)...));
};
}
};
现在,first.chain(second) 语法不适用于second 的多个输入。我们可以添加另一个方法:
template<class Sig>
struct adapter;
template<class Out, class... In>
struct adapter<Out(In...)>:std::function<Out(In...)>
{
using std::function<Out(In...)>::function;
template<class Next, class Result=std::invoke_result_t<Next const&, Out>>
adapter<Result(In...)> chain( Next next ) const& {
auto tmp=*this;
return std::move(tmp).chain(std::move(next));
}
template<class Next, class Result=std::invoke_result_t<Next, Out>>
adapter<Result(In...)> chain( Next next ) && {
return [self=std::move(*this), next=std::move(next)](In... in)->Result {
return next(self(std::forward<In>(in)...));
};
}
template<class...First>
adapter<Out(First...)> consume( adapter<In(First)>... src)&&
{
return [self=std::move(*this), ...src=std::move(src)](First... first)->Out
{
return self(src(std::forward<First>(first))...);
};
}
template<class...First>
adapter<Out(First...)> consume( adapter<In(First)>... src) const&
{
auto tmp = *this;
return std::move(tmp).consume( std::move(src)... );
}
};
但这有点远,不是吗?
Live example.
有些人对以非多态方式从值类型(如std::function)继承持怀疑态度。在这里,我认为几乎没有人在他们的正常头脑中存储指向std::functions 的指针;那些这样做的人,通常是在使用shared_ptr 技巧(处理多态破坏)。
但是,如果您担心,您可以这样做:
template<class Out, class... In>
struct adapter<Out(In...)>
{
using F = std::function<Out(In...)>;
F f;
// forward call operator
template<class...Args>
auto operator()(Args&&...args)const
-> std::invoke_result_t<F const&, Args&&...>
{
return f(std::forward<Args>(args)...);
}
// default all special member functions:
adapter()=default;
adapter(adapter const&)=default;
adapter(adapter &&)=default;
adapter& operator=(adapter const&)=default;
adapter& operator=(adapter &&)=default;
~adapter()=default;
// forward a few useful operations and ctors:
explicit operator bool() const { return (bool)f; }
template<class Fin>
requires (!std::is_same_v<Fin, adapter> && std::convertible_to<Fin, F>)
adapter( Fin fin ):f(std::forward<Fin>(fin)) {}
然后添加.chain 方法。
如您所见,这增加了相当多的代码。 Live example.