Is there a better way to chain together functions on streams? - c++

I have a series of functions that takes a stream as input and writes a transformation to an output stream. Right now the interface looks like this:
void phase1(std::istream& in, std::ostream& out);
void phase2(std::istream& in, std::ostream& out);
std::istream data = get_initial_data();
std::stringstream first_result;
phase1(data, first_result);
std::stringstream second_result;
phase2(first_result, second_result);
Is there an easier/more natural way to chain these calls without using Boost (sorry)?

I think you'd want to do:
(phase1 | phase2 | phase3)( in, out );
where all the glue happens for you. What more,
auto first_part = phase1|phase2;
auto second_part = phase3|phase4;
(first_part | second_part)( in, out );
should also work.
namespace stream {
template<class F=std::function<void(std::istream&, std::ostream&)>>
struct pipe {
F f;
void operator()( std::istream& in, std::ostream& out ) const {
f(in,out);
}
template<class O,
std::enable_if_t< !std::is_same<O, F>{} && std::is_convertible<O, F>{}, bool> = true
>
pipe ( pipe <O> o ):
f(std::move(o.f))
{}
pipe (F fin):
f(std::move(fin))
{}
};
template<class F>
pipe (F)->pipe <F>;
template<class First, class Second>
auto operator|( pipe <First> first, pipe <Second> second )
{
return pipe {[=](auto& in, auto& out){
std::stringstream intermediate;
first( in, intermediate );
second( intermediate, out );
}};
}
}
and now you can do:
std::istream data = get_initial_data();
( pipe {phase1} | pipe {phase2} )( data, out );
we can extend this to sources and sinks, allowing things to be glued to the input, but that often requires continuation passing style to handle lifetime issues.
You an also use pipe <> to handle any stream pipe object in a type-erased manner.
Live example.
If you want sources and sinks it looks like this:
namespace stream {
template<class Sig, class F=std::function<Sig>>
struct operation;
template<class R, class...Unused, class F>
struct operation<R(Unused...), F>
{
F f;
static_assert(
std::is_convertible< std::result_of_t< F const&(Unused...) >, R >{}
);
template<class...Args>
R operator()( Args&&...args ) const {
return static_cast<R>(f(std::forward<Args>(args)...));
}
template<class O,
std::enable_if_t< !std::is_same<O, F>{} && std::is_convertible<O, F>{}, bool> = true
>
operation ( operation<R(Unused...), O> o ):
f(std::move(o.f))
{}
operation (F fin):
f(std::move(fin))
{}
};
template<class F=std::function<void(std::istream&, std::ostream&)>>
struct pipe:operation<void(std::istream&, std::ostream&), F> {
using operation<void(std::istream&, std::ostream&), F>::operation;
};
template<class F>
pipe (F)->pipe <F>;
template<class First, class Second>
auto operator|( pipe <First> first, pipe <Second> second )
{
return pipe {[=](auto& in, auto& out){
std::stringstream intermediate;
first( in, intermediate );
second( intermediate, out );
}};
}
template<class F=std::function< void(std::function< void(std::ostream&)>) >>
struct source:operation<void(std::function< void(std::istream&)>), F> {
using operation<void(std::function< void(std::istream&)>), F>::operation;
};
template<class F>
source(F)->source<F>;
template<class F=std::function< void(std::function< void(std::ostream&)>) >>
struct sink:operation<void(std::function< void(std::ostream&)>), F> {
using operation<void(std::function< void(std::ostream&)>), F>::operation;
};
template<class F>
sink(F)->sink<F>;
template<class First, class Second>
auto operator|( source<First> src, pipe<Second> p ) {
return source{[=]( auto&& f ){
src([&](auto&& in){
std::stringstream ss;
p( in, ss );
f( ss );
});
}};
}
template<class First, class Second>
auto operator|( pipe<First> p, sink<Second> snk ) {
return sink{[=]( auto&& f ){
snk([&](auto&& out){
std::stringstream ss;
f(ss);
p(ss, out);
});
}};
}
void copy_f( std::istream& is, std::ostream& os ) {
char c;
while (is.get(c)) {
os << c;
}
}
inline pipe copy{copy_f};
template<class First, class Second>
void operator|( source<First> src, sink<Second> snk ) {
src([&](auto&& in){
snk([&](auto&& out){
copy( in, out );
});
});
}
}
you can then do:
using namespace stream;
auto src = source{[](auto&& f){
std::stringstream ss;
ss << "Hello world\n";
f(ss);
}};
auto snk = sink{[](auto&& f){
f(std::cout);
}};
src|copy|copy|copy|snk;
Live example
A source is a function object that in turn takes a function object, that it passes an istream& to.
A sink is a function object that in turn takes a function object, that it passes a ostream& to.
This double-function syntax deals with annoying lifetime issues, and lets you do cleanup before/after the client stream-user does stuff with the stream.
And a slightly more insane version that supports direct piping to/from streams is here.

Related

Advantages/Disadvantages of Many Nested Callbacks?

I have a work distribution scheme where every unit does some book-keeping and management and pass the task to next one in order chain such as; Lets say have 3 classes: Boss, Manager, Worker
class Boss
{
void do_async(Request req, std::function<void(Result)> callback)
{
//Find eligible manager etc.
manager.do_async(Boss_request(req,...),std::bind(&Boss::callback,this,callback,std::placeholders::_1));
}
void callback(std::function<void(Result)> main_callback,Boss_result res)
{
//some book keeping
main_callback(res.main_part);
}
};
class Manager
{
void do_async(Boss_request req, std::function<void(Boss_result)> boss_callback)
{
//Find eligible worker etc. add some data to request
worker.do_async(Manager_request(req,...),std::bind(&Manager::callback,this,boss_callback,std::placeholders::_1));
}
void callback(std::function<void(Boss_result)> boss_callback,Manager_result res)
{
//some book keeping
boss_callback(res.boss_part);
}
};
class Worker
{
void do_async(Manager_request req, std::function<void(Manager_result)> manager_callback)
{
//Do job async
work_async(Worker_task(req,...),std::bind(&Worker::callback,this,manager_callback,std::placeholders::_1));
}
void callback(std::function<void(Manager_result)> manager_callback,Worker_result res)
{
//some book keeping
manager_callback(res.manager_part);
}
};
As you can see I am extensively using std::bind, std::function and std::placeholder. Does this approach has any advantages/disadvantages? if not preferable, so what is the better way to do it? Would using lambda functions be possible/preferable(as performance or code-quality) in this state?
Edit: Why do I need asynchronous access in every level, instead of only first level? Because between each classes there is a many-to-many relationship. I have couple of layers of processing units (Boss or Manager or Worker) which can order anyone in next layer. When a unit orders the job to next one in line. It must be free immediately to take new orders from above.
I haven't used directly lambda because callbacks can be a little bit large and may make it harder to read. But code-quality can be sacrificed if there is any significant performance penalty.
What you are doing here is piping data around. Embrace the pipe.
namespace chain {
template<class T, class Base=std::function<void(T)>>
struct sink:Base{
using Base::operator();
using Base::Base;
};
template<class T, class F>
sink<T> make_sink( F&& f ) {
return {std::forward<F>(f)};
}
template<class T>
using source=sink<sink<T>>;
template<class T, class F>
source<T> make_source( F&& f ) {
return {std::forward<F>(f)};
}
template<class T>
source<std::decay_t<T>> simple_source( T&& t ) {
return [t=std::forward<T>(t)]( auto&& sink ) {
return sink( t );
};
}
template<class In, class Out>
using pipe = std::function< void(source<In>, sink<Out>) >;
template<class In, class Out>
sink<In> operator|( pipe<In, Out> p, sink<Out> s ) {
return [p,s]( In in ) {
p( [&]( auto&& sink ){ sink(std::forward<In>(in)); }, s );
};
}
template<class In, class Out>
source<Out> operator|( source<In> s, pipe<Out> p ) {
return [s,p]( auto&& sink ) {
p( s, decltype(sink)(sink) );
};
}
template<class T>
std::function<void()> operator|( source<T> in, sink<T> out ) {
return [in, out]{ in(out); };
}
template<class In, class Mid, class Out>
pipe<In, Out> operator|( pipe<In, Mid> a, pipe<Mid, Out> b ) {
return [a,b]( source<In> src, sink<Out> dest ) {
b( src|a, dest );
// or a( src, b|dest );
// but I find pipe|sink -> sink to be less pleasing an implementation
};
}
}//namespace
Then write these:
pipe<Request, Result> Boss::work_pipe();
pipe<Boss_request, Boss_result> Manager::work_pipe();
pipe<Boss_request, Manager_request> Manager::process_request();
pipe<Manager_request, Manager_result> Manager::do_request();
pipe<Manager_result, Boss_results> Manager::format_result();
pipe<Manager_request, Manager_result> Worker::work_pipe();
and similar for Worker and Boss.
pipe<Request, Result> Boss::work_pipe() {
return process_request() | do_request() | format_result();
}
pipe<Boss_request, Boss_result> Manager::work_pipe() {
return process_request() | do_request() | format_result();
}
pipe<Manager_request, Manager_result> Worker::work_pipe() {
return process_request() | do_request() | format_result();
}
then:
pipe<Manager_request, Manager_result> Manager::do_request() {
return [this]( source<Manager_request> src, sink<Manager_result> dest ) {
// find worker
worker.do_request( src, dest );
};
}
pipe<Manager_output, Boss_result> Manager::format_result() {
return [this]( source<Manager_output> src, sink<Boss_result> dest ) {
src([&]( Manager_output from_worker ) {
// some book keeping
dest( from_worker.boss_part );
});
};
}
now, I made sources "sinks for sinks", because it permits a source (or a pipe) to generate 1, 0, or many messages from one invocation. I find this useful in many cases, but it does make writing pipes a bit stranger.
You can also write this in c++14 without using std::function at all, by simply applying "i am a sink" and "i am a source" and "i am a pipe" tags to lambdas (via composition, like override) then blindly hooking things up with | and hoping their type are compatible.
To do_sync, you just do this:
void Boss::do_async( Request req, sink<Result> r ) {
work_async( simple_source(req) | work_pipe() | r );
}
ie, the entire computation can be bundled up and moved around. This moves the threading work to the top.
If you need the async thread implementation to be at the bottom, you can pipe up the earlier work and pass it down.
void Boss::do_async( source<Request> req, sink<Result> r ) {
find_manager().do_async( req|process_request(), format_result()|r );
}
void Manager::do_async( source<Boss_request> req, sink<Boss_result> r ) {
find_worker().do_async( req|process_request(), format_result()|r );
}
void Worker::do_async( source<Manager_request> req, sink<Manager_result> r ) {
work_async( req|process_request()|do_request()|format_result()|r );
}
because of how the sink/source/pipes compose, you can choose what parts of the composition you pass down and which parts you pass up.
The std::function-less version:
namespace chain {
struct pipe_tag{};
struct sink_tag{};
struct source_tag{};
template<class T, class=void>
struct is_source:std::is_base_of<source_tag, T>{};
template<class T, class=void>
struct is_sink:std::is_base_of<sink_tag, T>{};
template<class T, class=void>
struct is_pipe:std::is_base_of<pipe_tag, T>{};
template<class F, class Tag>
struct tagged_func_t: F, Tag {
using F::operator();
using F::F;
tagged_func_t(F&& f):F(std::move(f)) {}
};
template<class R, class...Args, class Tag>
struct tagged_func_t<R(*)(Args...), Tag>: Tag {
using fptr = R(*)(Args...);
fptr f;
R operator()(Args...args)const{
return f( std::forward<Args>(args)... );
}
tagged_func_t(fptr fin):f(fin) {}
};
template<class Tag, class F>
tagged_func_t< std::decay_t<F>, Tag >
tag_func( F&& f ) { return {std::forward<F>(f)}; }
template<class F>
auto as_pipe( F&& f ) { return tag_func<pipe_tag>(std::forward<F>(f)); }
template<class F>
auto as_sink( F&& f ) { return tag_func<sink_tag>(std::forward<F>(f)); }
template<class F>
auto as_source( F&& f ) { return tag_func<source_tag>(std::forward<F>(f)); }
template<class T>
auto simple_source( T&& t ) {
return as_source([t=std::forward<T>(t)]( auto&& sink ) {
return sink( t );
});
}
template<class Pipe, class Sink,
std::enable_if_t< is_pipe<Pipe>{} && is_sink<Sink>{}, bool> = true
>
auto operator|( Pipe p, Sink s ) {
return as_sink([p,s]( auto&& in ) {
p( [&]( auto&& sink ){ sink(decltype(in)(in)); }, s );
});
}
template<class Source, class Pipe,
std::enable_if_t< is_pipe<Pipe>{} && is_source<Source>{}, bool> = true
>
auto operator|( Source s, Pipe p ) {
return as_source([s,p]( auto&& sink ) {
p( s, decltype(sink)(sink) );
});
}
template<class Source, class Sink,
std::enable_if_t< is_sink<Sink>{} && is_source<Source>{}, bool> = true
>
auto operator|( Source in, Sink out ) {
return [in, out]{ in(out); };
}
template<class PipeA, class PipeB,
std::enable_if_t< is_pipe<PipeA>{} && is_pipe<PipeB>{}, bool> = true
>
auto operator|( PipeA a, PipeB b ) {
return as_pipe([a,b]( auto&& src, auto&& dest ) {
b( src|a, dest );
// or a( src, b|dest );
// but I find pipe|sink -> sink to be less pleasing an implementation
});
}
template<class T>
using sink_t = tagged_func_t< std::function<void(T)>, sink_tag >;
template<class T>
using source_t = tagged_func_t< std::function<void(sink_t<T>)>, source_tag >;
template<class In, class Out>
using pipe_t = tagged_func_t< std::function<void(source_t<In>, sink_t<Out>)>, pipe_tag >;
}
which does fewer type checks, but gets rid of type erasure overhead.
The sink_t, source_t and pipe_t typedefs are useful when you need to type-erase them.
"Hello world" example using the non-type erasure version.

How to convert std::future<T> to std::future<void>?

I have a situation where I have a std::future<some_type> resulting from a call to API A, but need to supply API B with a std::future<void>:
std::future<some_type> api_a();
void api_b(std::future<void>& depend_on_this_event);
In the absence of proposed functionality such as .then() or when_all(), is there any efficient way to throw away the value attached to a std::future<T> and be left only with the underlying std::future<void> representing the event's completion?
Something like the following could work but would be potentially inefficient:
auto f = api_a();
f.wait();
auto void_f = std::async(std::launch::defer, []{});
api_b(void_f);
The best you can get is probably this:
auto f = api_a();
auto void_f = std::async(std::launch::deferred,[fut = std::move(f)]{ fut.wait();});
api_b(void_f);
template<class U>
struct convert_future_t {
template<class T>
std::future<U> operator()( std::future<T>&& f ) const {
return std::async(std::launch::deferred,
[f=std::move(f)]()->U{ return f.get(); }
);
}
}
template<>
struct convert_future_t<void> {
template<class T>
std::future<void> operator()( std::future<T>&& f ) const {
return std::async(std::launch::deferred,
[f=std::move(f)]()->void{ f.get(); }
);
}
}
template<class U, class T>
std::future<U> convert_future( std::future<T>&& f ) {
return convert_future_t<U>{}(std::move(f));
}
this is a generic version of #sbabbi's answer.
api_b( convert_future<void>( api_a() ) );
that allows for any target and dest type to work transparently.
The large downside to this approach is that the resulting future is a deferred future wrapping a (possibly async) future, which means that .wait_for() and .ready() APIs do not work like async futures do. The returned future will never be ready until waited.
So we can improve this marginally:
template<class T>
struct ready_future_t {
template<class...Us>
std::future<T> operator()( Us&&...us ) const {
std::promise<T> p;
p.set_value(T(std::forward<Us>(us)...));
return p.get_future();
}
};
template<>
struct ready_future_t<void> {
using T=void;
// throws away the Us&&...s
template<class...Us>
std::future<T> operator()( Us&&...us ) const {
std::promise<T> p;
p.set_value();
return p.get_future();
}
};
template<class T, class...Us>
std::future<T> ready_future(Us&&...us){
return ready_future_t<T>{}(std::forward<Us>(us)...);
}
template<class U>
struct convert_future_t {
template<class T>
std::future<U> operator()( std::future<T>&& f ) const {
if (f.wait_for(0ms)==std::future_status::ready)
return ready_future<U>(f.get());
return std::async(std::launch::deferred,
[f=std::move(f)]()->U{ return f.get(); }
);
}
};
template<>
struct convert_future_t<void> {
template<class T>
std::future<void> operator()( std::future<T>&& f ) const {
if (f.wait_for(0ms)==std::future_status::ready)
return ready_future<void>();
return std::async(std::launch::deferred,
[f=std::move(f)]()->void{ f.get(); }
);
}
};
where at least if the future was already ready by the time we converted it, the returned future is also ready.
live example

template function with corresponding parameters to subset of tuple types

I would like to write function as this find:
multi_set<int, string, double, myType> m; //vector of tuples
m.insert(/*some data*/);
m.find<1,2>("something",2.123);
Or
m.find<0,3>(1,instanceOfMyType);
m.find<1>("somethingelse");
Where find can be parametrized corresponding to any subset of tuple parameters.
My code so far:
template <typename ... T>
class multi_set{
typedef tuple < T... > Tuple;
vector<tuple<T...>> data = vector<tuple<T...>>();
public:
void insert(T... t){
data.push_back(tuple<T...>(t...));
}
template<size_t ... Pos>
void find(???){
// then I would like to use those params to search through data and
// return first matching item
}
}
// test whether a particular tuple is a match
template<size_t... Pos>
static bool is_match(const Tuple& tuple, const typename std::tuple_element<Pos, Tuple>::type &... args) {
std::initializer_list<bool> results = { (std::get<Pos>(tuple) == args)... };
return std::all_of(results.begin(), results.end(), [](bool p) { return p; });
}
// Find the first one that is a match.
template<size_t... Pos>
typename vector<Tuple>::const_iterator find(const typename std::tuple_element<Pos, Tuple>::type &... args) const {
return std::find_if(data.begin(), data.end(), [&](const Tuple & tup) { return is_match<Pos...>(tup, args...); });
}
It's also possible to have find take a type parameter pack and perfectly forward, rather than taking fixed types with tuple_element. The benefit is that you can avoid an unnecessary conversion if == is transparent. The cost is that you can't take anything that can't be perfectly forwarded any more (e.g., braced initializer lists, 0 as a null pointer constant). A side benefit appears to be that MSVC 2013 doesn't choke on this version:
// test whether a particular tuple is a match
template<size_t... Pos, class... Args>
static bool is_match(const Tuple& tuple, Args&&... args) {
std::initializer_list<bool> results = { (std::get<Pos>(tuple) == std::forward<Args>(args))... };
return std::all_of(results.begin(), results.end(), [](bool p) { return p; });
}
// Find the first one that is a match.
template<size_t... Pos, class... Args>
typename vector<Tuple>::const_iterator find(Args&&... args) const {
return std::find_if(data.begin(), data.end(), [&](const Tuple & tup) { return is_match<Pos...>(tup, std::forward<Args>(args)...); });
}
You should look into boost::multi_index. It is very close to what you are looking for.
http://www.boost.org/doc/libs/1_54_0/libs/multi_index/doc/tutorial/index.html
This is a function that takes a seed value, and a set of lambdas. It feeds that seed value through each of the lambdas in turn:
template<class... Fs, class R>
R chain( R r, Fs&&... fs ) {
using in_order = int[];
(void)(in_order{0,
(
(r = std::forward<Fs>(fs)( r ))
, void(), 0
)...
});
return r;
}
Inside your class, we use the above:
template<size_t... Pos, class...Us>
typename std::vector<Tuple>::const_iterator
find(Us const&... us) const {
return std::find_if(
data.begin(), data.end(),
[&](const Tuple & tup) {
return chain(
true,
[&](bool old){
return old && (std::get<Pos>(tup) == us);
}...
);
}
);
}
this compiles in clang, but not g++ 4.9.2 -- g++ doesn't like parameter packs inside lambdas.
Note the fact we take Us const&... -- this allows for transparent ==, which is important in some cases. std::string == char const* is a classic example, where if you force find to take the same value as in the tuple, you'll force a needless allocation in calling find.
In C++1z, the chain call can be replaced with:
( ... && (std::get<Pos>(tup) == us) )
which is conceptually identical, but much easier to read. This is known as a "fold expression".
Now, a problem with the above is that it uses forwarding references, which causes imperfect forwarding problems of perfect forwarding.
The most annoying of which is the inability to use {} to construct arguments.
If we use matching types, we instead force non-transparent comparison, which can be expensive (examine std::string compared to "hello this is a c string" -- it causes possibly allocation if we force the c string into a std::string.)
A way around this is to type erase down to the concept of equality with a given type.
template<class...>struct voider{using type=void;};
template<class...Ts>using void_t=typename voider<Ts...>::type;
template<class T>struct tag{using type=T;};
template<class...>struct types{using type=types;};
template<class T>
using block_deduction = typename tag<T>::type;
template<class F, class Sig, class T=void>
struct erase_view_op;
template<class F, class R, class...Ts, class T>
struct erase_view_op<F, R(Ts...), T>
{
using fptr = R(*)(void const*, Ts&&...);
fptr f;
void const* ptr;
private:
template<class U>
erase_view_op(U&& u, int):
f([](void const* p, Ts&&...ts)->R{
U& u = reinterpret_cast<U&>( *static_cast<std::decay_t<U>*>(const_cast<void*>(p)) );
return F{}( u, std::forward<Ts>(ts)... );
}),
ptr( static_cast<void const*>(std::addressof(u)) )
{}
public:
template<class U, class=std::enable_if_t< !std::is_same<std::decay_t<U>,erase_view_op>{} && std::is_convertible< std::result_of_t<F(U,Ts...)>, R >{} >>
erase_view_op(U&& u):erase_view_op( std::forward<U>(u), 0 ){}
template<class U=T, class=std::enable_if_t< !std::is_same<U, void>{} >>
erase_view_op( block_deduction<U>&& u ):erase_view_op( std::move(u), 0 ){}
erase_view_op( erase_view_op const& ) = default;
erase_view_op( erase_view_op&& ) = default;
R operator()( Ts... ts ) const {
return f( ptr, std::forward<Ts>(ts)... );
}
};
struct equality {
template<class lhs, class rhs>
bool operator()(lhs const& l, rhs const& r)const {
return l==r;
}
};
template<class T>
using erase_equal_to = erase_view_op< equality, bool(T const&), T >;
using string_equal_to = erase_equal_to< std::string >;
int main() {
static_assert( std::is_same< bool, std::result_of_t< std::equal_to<>(decltype("hello"), std::string const&) > >{}, "hmm" );
string_equal_to s = "hello";
string_equal_to s2 = {{"hello"}};
(void)s2;
std::string x = "hello";
std::string y = "jello";
std::cout << s(x) << s(y) << '\n';
}
then we rewrite find:
template<size_t... Pos>
typename std::vector<Tuple>::const_iterator
find(erase_equal_to< std::remove_reference_t<std::tuple_element_t<Pos, Tuple>> >... us) const {
return std::find_if(
data.begin(), data.end(),
[&](const Tuple & tup) {
return chain(
true,
[&](bool old){
return old && us(std::get<Pos>(tup));
}...
);
}
);
}
which does both transparent equality and allows {} based construction (well, it does require {{}} based construction -- the outer to say we are constructing the eraser, the inner to construct the T).

Transforming n binary calls to one n-ary call in C++?

We have a helper function in our codebase to concatenate two (Windows) path strings:
CString AppendPath(CString const& part1, CString const& part2);
It is often used in this way:
const CString filePath = AppendPath(AppendPath(AppendPath(base, toplevel), sub1), filename);
This is rather acceptable, but it got me wondering if there is some possibility in C++ (or C++0x) to use a (template?) function to chain binary function calls together.
That is, given a function T f(T arg1, T arg2) is it possible to write a function T ncall(FnT fn, T arg1, T arg2, T arg3, ...) that will call f like in my example above and return the result?
// could roughly look like this with my example:
const CString filePath = ncall(&AppendPath, base, toplevel, sub1, filename);
Please, this question is about the transformation and not about the best way to handle or concatenate path strings!
Edit: Thanks to deft_code's answer for providing the correct term for what I was asking for: Fold (higher-order function). (Note that I have settled on accepting the answer of Matthieu because his solution does not require C++0x.)
Without C++0x, it's also possible to use chaining (I don't recommend overloading the comma operator, the syntax gets weird).
The syntax is somewhat different, but very close:
CString const Path = AppendPath(base)(toplevel)(sub1)(filename);
This is done simply by creating a temporary object that will perform the catenation through an overload of operator() and which will be implicitly convertible through operator CString() const.
class AppenderPath
{
public:
AppenderPath(){}
AppenderPath(CString s): _stream(s) {}
AppenderPath& operator()(CString const& rhs) {
_stream += "/";
_stream += rhs;
return *this;
}
operator CString() const { return _stream; }
private:
CString _stream;
};
Then, you tweak AppendPath to return such an object:
AppenderPath AppendPath(CString s) { return AppenderPath(s); }
(Note, actually you could directly name it AppendPath)
Making it generic as per #Martin's suggestion:
#include <iostream>
#include <string>
template <typename L, typename R>
class Fold1l
{
public:
typedef void (*Func)(L&, R const&);
Fold1l(Func func, L l): _func(func), _acc(l) {}
Fold1l& operator()(R const& r) { (*_func)(_acc, r); return *this; }
operator L() const { return _acc; }
private:
Func _func;
L _acc;
};
// U is just to foil argument deduction issue,
// since we only want U to be convertible into a R
template <typename R, typename L, typename U>
Fold1l<R,L> fold1l(void (*func)(L&, R const&), U l) {
return Fold1l<R,L>(func, l);
}
void AppendPath(std::string& path, std::string const& next) {
path += "/"; path += next;
}
int main() {
std::string const path = fold1l(AppendPath, "base")("next");
std::cout << path << std::endl;
}
Code validated on ideone.
In C++0x, you can use variadic templates. Something like this, perhaps:
template<typename... Args>
CString AppendAllPaths(CString const& part1, Args const&... partn)
{
return AppendPath(part1, AppendAllPaths(partn...));
}
template<>
CString AppendAllPaths(CString const& part1, CString const& part2)
{
return AppendPath(part1, part2);
}
Making Martinho Fernandes' solution more generic:
#define AUTO_RETURN(EXPR) -> decltype(EXPR) \
{ return EXPR; }
template<class F, class Arg1, class ...Args>
auto n_binary_to_1_nary(F func, Arg1 &&a, Args &&...rest)
AUTO_RETURN(func(std::forward<Arg1>(a),
n_binary_to_1_nary(func, std::forward<Args>(rest)...))))
template<class F, class Arg1, class Arg2>
auto n_binary_to_1_nary(F func, Arg1 &&a, Arg2 &&b)
AUTO_RETURN(func(std::forward<Arg1>(a), std::forward<Arg2>(b)))
Use:
n_binary_to_1_nary(&AppendPath, base, toplevel, sub1, filename)
However, AppendPath could simply be written in this style:
CString AppendPath(CString const &part1, CString const &part2); // existing
template<class ...Args>
CString AppendPath(CString const &a, CString const &b, Args const &...rest) {
return AppendPath(AppendPath(a, b), rest...);
}
You can, of course, add this overload and use it transparently in your code.
Or pass an initializer_list:
CString filePath = AppendPath({base, toplevel, sub1, filename});
Code:
template<class Iter>
CString AppendPath(Iter begin, Iter end) {
CString result;
if (begin == end) {
assert(!"reporting an error (however you like) on an empty list of paths"
" is probably a good idea");
}
else {
result = *begin;
while (++begin != end) {
result = AppendPath(result, *begin);
}
}
return result;
}
template<class C>
CString AppendPath(C const &c) {
return AppendPath(c.begin(), c.end());
}
Notice the last AppendPath works with any STL-like container. You can also add these overloads to your code and use them transparently.
In this specific case of calling AppendPath I'd just write an overload of the function which has as its implementation your second line of code.
In the general case I'd write a series of templates:
template<typename T>
T ncall(T (*fn)(T const&,T const&), T const& p1, T const& p2, T const& p3){
return fn(fn(p1, p2), p3);
}
template<typename T>
T ncall(T (*fn)(T const&,T const&), T const& p1, T const& p2, T const& p3, T const& p4){
return ncall(fn, fn(p1, p2), p3, p4);
}
template<typename T>
T ncall(T (*fn)(T const&,T const&), T const& p1, T const& p2, T const& p3, T const& p4, T const& p5){
return ncall(fn, fn(p1, p2), p3, p4, p5);
}
Which I'm sure could be easily generated automatically.
Given a function T f(T arg1, T arg2) is it possible to write a function T ncall(FnT fn, T arg1, T arg2, T arg3, ...) that will call f like in my example above and return the result?
Everyone is soo close to a general foldl implementation. Here is an even more general solution than the question asked. It accepts functions like T f(T arg1, T arg2) as well as T1 f(T2 arg1, T3 arg2). Also I named the function foldl in homage to its functional roots.
#define AUTO_RETURN( EXPR ) -> decltype( EXPR ) \
{ return EXPR; }
template< typename BinaryFunc, typename First, typename Second >
auto foldl( BinaryFunc&& func, First&& first, Second&& second )
AUTO_RETURN( func( std::forward<First>(first), std::forward<Second>(second) ) )
template<typename BinaryFunc,typename First, typename Second, typename... Rest >
auto foldl( BinaryFunc&& func, First&& first, Second&& second, Rest&&... rest )
AUTO_RETURN(
foldl(
std::forward<BinaryFunc>(func),
std::forward<decltype( func(first,second) )>(
func( std::forward<First>(first), std::forward<Second>(second) )),
std::forward<Rest>(rest)... )
)
An example of how this would solve your problem:
auto path = foldl( &AppendPath, base, toplevel, sub1, filename );
Another example showing off all of foldl's strength:
struct stream
{
template< typename T >
std::ostream& operator()( std::ostream& out, T&& t ) const
{
out << std::forward<T>(t);
return out;
}
};
struct Foo
{
Foo( void ) = default;
Foo( const Foo& ) = delete;
Foo& operator=( const Foo& ) = delete;
};
std::ostream& operator << ( std::ostream& out, const Foo& )
{
out << "foo";
return out;
}
int main()
{
foldl( stream(), std::cout, 1, ' ', 1.1, ' ', Foo{}, '\n' );
}
See the output / code in action at ideone.

Is there a legal way to print tuples and pairs using operator<<?

I have a set of templates/functions that allow me to print a tuple/pair assuming that each type in the tuple/pair has operator<< defined for it. Unfortunately, due to 17.4.3.1, it is illegal to add my operator<< overloads to std. Is there another way to get ADL to find my operator<<? If not, is there any actual harm in wrapping my overload in namespace std{}?
The code for anyone interested: (I'm using gcc-4.5)
namespace tuples {
using ::std::tuple;
using ::std::make_tuple;
using ::std::get;
namespace detail {
template< typename...args >
size_t size( tuple<args...> const& )
{
return sizeof...(args);
};
template<size_t N>
struct for_each_ri_impl
{
template<typename Func, typename Tuple>
void operator()(Func func, Tuple const& arg)
{
for_each_ri_impl<N-1>()(func, arg );
func( get<N>( arg ), size(arg) - N - 1 );
}
};
template<>
struct for_each_ri_impl<0>
{
template<typename Func, typename Tuple>
void operator()(Func func, Tuple const& arg)
{
func( get<0>( arg ), size(arg) - 1 );
}
};
}//detail
template<typename Func, typename ... Args>
void for_each_ri( tuple<Args...>const& tup, Func func )
{
detail::for_each_ri_impl< sizeof...(Args)-1>()( func, tup );
}
struct printer {
std::ostream& out;
const std::string& str;
explicit printer( std::ostream& out=std::cout, std::string const& str="," ) : out(out), str(str) { }
template<typename T>void operator()(T const&t, size_t i=-1) const { out<<t; if(i) out<<str; }
};
//Should this next line go into namespace std? Is there another way?
template<typename ... Args>
std::ostream& operator<<(std::ostream& out, std::tuple< Args... > const& tup)
{
out << '[';
tuples::for_each_ri( tup, tuples::printer(out,", ") );
return out << ']';
}
} //tuples
//Edits --
int main()
{
using namespace std;
cout<<make_tuple(1,'a',"Hello")<<endl;
return 0;
}
Compiling the above yields:
test.cpp: In function 'int main()':
test.cpp:69:31: error: cannot bind 'std::ostream' lvalue to 'std::basic_ostream&&' > /opt/local/include/gcc45/c++/ostream:579:5: error: initializing argument 1 of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char, _Traits = std::char_traits, _Tp = std::tuple]'
Put your own light wrapper class around it and then overload operator<< to use that. However beware that even if your light wrapper has an implicit constructor you will probably still need to use it explicitly when you pass it to operator<<
template< typename ...VA_ARGS >
struct format_tuple
{
typedef tuple<VA_ARGS...> tuple_type;
// any format variables
const tuple_type & tup;
format_tuple( const tuple_type& t): tup(t) {}
};
template< typename ...VA_ARGS > format_tuple<VA_ARGS...> makeFormatTuple( const tuple<VA_ARGS...> & t )
{
return format_tuple( t );
}
template<typename ...VA_ARGS>
std::ostream& operator<<( std::ostream& os, const format_tuple<VA_ARGS...> & ft )
{
// original implementation
}
This is an outline as I'm not sure exactly how to do it with variadic templates although it should be possible. You can easily implement several versions though with 1, 2, 3, etc.parameters, eg:
template<typename T1, typename T2, typename T3>
class format_tuple_3; //etc
template<typename T1, typename T2, typename T3>
format_tuple_3<T1, T2, T3> makeFormatTuple( tuple<T1,T2,T3> const&); //etc
The harm is someone else (such as in a third party library you want to use) also adding these declarations to std. Even if theirs behave identically, you'll violate the ODR.
Just put these in your project's namespace:
namespace kitsune_ymg {
// Op<< overloads here.
// Your "normal" stuff.
void normal_stuff() {
std::cout << std::pair<int, int>(42, 3);
}
And then anything in your project can use them.
I'm still not sure exactly why this doesn't work for you, but it seems you want something like:
namespace kitsune_ymg {
namespace tuples {
// Op<< overloads here.
}
using namespace tuples;
// Your "normal" stuff.
}
namespace completely_separate_project {
using kitsune_ymg::tuples;
// Now you can use those op<< overloads in this scope, too.
void perfectly_normal_beast() {
std::cout << std::pair<int, int>(42, 3);
}
}
You mustn't add your own operator<< to std. However, you can write an adapter for tuples, or one for streams, and use that, with a minimal amount of change to the call sites.
I'll assume C++17 or newer (to use structured bindings and fold expressions), although the question is obviously much older.
Adapt the tuple
#include <ostream>
#include <tuple>
template<typename... Args>
struct printable_tuple
{
typedef std::tuple<Args...> tuple_type;
const tuple_type& t;
// implicit converting constructor
printable_tuple(const tuple_type& t)
: t(t)
{}
};
template<typename... Args>
std::ostream& operator<<(std::ostream& os, const printable_tuple<Args...>& tuple)
{
const char *sep = "";
os << '[';
std::apply([&os,&sep](auto&&...args){((os << sep << args, sep = ","),...);}, tuple.t);
return os << ']';
}
#include <iostream>
int main()
{
std::cout << format_tuple{std::tuple{1,'a',"Hello"}} << '\n';
}
This is the least intrusive, as we can use the returned stream normally (if (os << tuple), for instance), but it requires wrapping each and every argument.
Adapt the stream
#include <tuple>
template<typename Stream>
class tuple_ostream
{
Stream& os;
public:
// conversions from and to Stream
tuple_ostream(Stream& os) : os{os} {}
operator Stream&() const { return os; };
// generic forwarding <<
template<typename T>
tuple_ostream& operator<<(const T&t)
{
os << t;
return *this;
}
// overload for tuples
template<typename... Args>
tuple_ostream& operator<<(const std::tuple<Args...>&t)
{
const char *sep = "";
os << '[';
std::apply([this,&sep](auto&&...args){((os << sep << args, sep = ","),...);}, t);
os << ']';
return *this;
}
};
#include <iostream>
int main()
{
tuple_ostream{std::cout} << std::tuple{1,'a',"Hello"} << '\n';
}
Adapting the stream is obviously simpler when we need to write several tuples to the same stream, but we can no longer directly use the returned stream as the original unless we add more functions to the wrapper.
Hat-tip to CashCow's answer for a starting point for this one.