ので配管はに関するデータを格納ではない流れであるだろう
template <typename T>
class Pipe {
T data;
public:
Pipe (T data) : data(data) {}
const T& unpack() const { return data; }
T& unpack() { return data; }
template <typename F>
auto operator| (F reducer) -> decltype(reducer(std::declval<T>()))
{
return Pipe<decltype(reducer(data))>(reducer(data));
}
Pipe operator|| (T& destination) const
{
destination = unpack();
return *this;
}
};
template <typename T>
Pipe<T> MakePipe(T data) {
return Pipe<T>(data);
}
を。
namespace plumbing {
// tags to identify plumping components:
struct pipe_tag {};
struct src_tag{};
struct sink_tag{};
// this lets us tag function objects. To handle function pointers,
// we need a specialization.
template<class F, class Tag>
struct tagged_f:F,Tag{
using F::F;
tagged_f(F&& f):F(std::move(f)){}
};
template<class Tag, class F>
tagged_f<F,Tag> tag(F f){ return {std::move(f)}; }
// detect various tags:
template<class F> using is_pipe = std::is_base_of<pipe_tag, F>;
template<class F> using is_src = std::is_base_of<src_tag, F>;
template<class F> using is_sink = std::is_base_of<sink_tag, F>;
// type erased versions of the plumbing components
// useful to store the end result of a plumbing job:
template<class T>
using gen_sink = tagged_f<std::function<void(T)>, sink_tag>;
template<class T>
using gen_src = tagged_f<std::function<void(gen_sink<T>)>, src_tag>;
template<class In, class Out>
using gen_pipe = tagged_f<std::function<void(gen_src<In>, gen_sink<Out>)>, pipe_tag>;
// SFINAE helper using the is_X templates above:
template<class T, template<class...>class Test>
using check=std::enable_if_t< Test<T>{}, bool >;
// really simple source, pipe and sink helpers:
template<class T>
auto simple_src(T in){
return tag<src_tag>([=](auto&& sink){ sink(in); });
}
template<class F>
auto simple_pipe(F f){
return tag<pipe_tag>([=](auto&& src, auto&& sink){
src([&](auto&& in){sink(f(in));});
});
}
template<class V>
auto vector_sink(V& v){
return tag<sink_tag>([&](auto&&t){ v.push_back(decltype(t)(t)); });
}
// operator| implementations:
// Src|Pipe is a Src:
template<class Src, class Pipe,
check<Src, is_src> =true,
check<Pipe, is_pipe> =true
>
auto operator|(Src src, Pipe pipe){
return tag<src_tag>([=](auto&& sink){
pipe(src, sink);
});
}
// Pipe|Sink is a Sink:
template<class Pipe, class Sink,
check<Sink, is_sink> =true,
check<Pipe, is_pipe> =true
>
auto operator|(Pipe pipe, Sink sink){
return tag<sink_tag>([=](auto&& t){
pipe(simple_src(t), sink);
});
}
// Pipe|Pipe is a Pipe:
template<class PipeA, class PipeB,
check<PipeA, is_pipe> =true,
check<PipeB, is_pipe> =true
>
auto operator|(PipeA a, PipeB b){
return tag<pipe_tag>([=](auto&& src, auto&& sink){
b(src|a, sink);
});
}
// Src|Sink is a callable object on 0 arguments:
template<class Src, class Sink,
check<Src, is_src> =true,
check<Sink, is_sink> =true
>
auto operator|(Src src, Sink sink){
return [=]{ src(sink); };
}
}
Live example。
これは、あなたがステートレスパイプチェーンを設定でき、タイプは(gen_pipe<In,Out>
を使用して)、それを消去し、データの1つのチャンクがゼロまたは多くなっています(あなたが終端記号を追加した場合)、バッファや文字列に取り組むなど
Tのシンクは、TのソースこれはUのTからパイプがある以上1
を生成するためにそれらを可能にするTのシンクを消費する機能であるT.
を消費する機能でありますTのソースとUのシンクの両方をとる関数。
データはパイプに格納されず、むしろパイプを介して流れます。
using namespace plumbing;
std::vector<int> v;
// build pipe, don't run it:
auto code = simple_src(7)|simple_pipe([](auto x){return x*2;})|vector_sink(v);
// run pipe:
code(); // v contains {14}
// print:
for (auto x:v)
std::cout << x << "\n";
これらのパイプはタイプされておらず、接続時にタイプが一致していることを確認します。
auto print_sink = tag<sink_tag>([](auto&& x){ std::cout << x; });
この同じシンクは、データの複数の異なる種類に接続することができます。
ですから、このようなシンクを持つことができます。
auto hello_world_src = tag<src_tag>([](auto&& sink) {
for (char c : "hello world")
sink(c);
});
次いで
(hello_world_src|print_sink)();
プリント"hello world"
。一方、
(simple_src(3.14)|print_sink)();
プリント3.14
。
私たちも、空想を取得することができます:
auto foreach_src = [](auto&& c){
return tag<src_tag>([c=decltype(c)(c)](auto&& sink) {
for(auto&& x:c)
sink(decltype(x)(x));
});
};
これは、範囲をとり、コンテナの要素の上にソースを返す関数です。
auto foreach_pipe = tag<pipe_tag>([foreach_src](auto&& src, auto&& sink) {
src([&](auto&& c) {
foreach_src(c)(sink);
});
});
これはパイプです。それは範囲のソースと要素のシンクを取り、それらを接続します。
With more examples
ワウ。ありがとう、これは美しい解決策です。 – StargazingTux