Hi Codeforces,
Here's a blog on easy IO I've meant to write for quite some time and was finally able to put together.
Motivation: For many contests, all code needs to be produced from scratch in contest, i.e. no templates unless you are willing to write them in contest. This means that if you are going to have a template, it needs to be planned out aptly to minimize the time it takes to write.
One of the best things about templates is the ability to have easy IO functions. This means writing re(a,b,c,d)
instead of cin >> a >> b >> c >> d
and similar (such as something with scanf
and formatters). The problem is, creating such functions from scratch can take a very long time if done traditionally (blatant recursive calls), and this also loses some efficiency in runtime.
But I recently came upon a novel method that can streamline this very process called operator forwarding.
The process is extremely simple: you can write the entire set of functions in only four lines of code and no extra hassle!
The first thing you need to know is that functions like re
and pr
need to be based on variadic template arguments (i.e., a comma separated chain). We can make a reusable macro like the below to handle any desired function x
. The semantics here are that the arguments are given as universal rvalue references for flexibility.
#define m1(x) template<class T, class... U> void x(T&& a, U&&... b)
But how do we write the function bodies? This is where we notice that the arguments are in the form of a parameter pack, meaning that we can use perfect forwarding. This avoids recursion, not only speeding up runtime by avoiding recursive call overhead but even speeding up coding time (one line instead of many). In particular, we can make a second macro that hosts our forwarding pack:
#define m2(x) (int[]){(x forward<U>(b),0)...}
Now, based on just these two macros, we can write the generalized easy IO with surprising ease:
m1(pr) { cout << forward<T>(a); m2(cout << " " <<); cout << "\n"; }
m1(re) { cin >> forward<T>(a); m2(cin >>); }
Just like that, we have the capacity to write an IO template extremely quickly, in only four lines total! These lines are not only easy to memorize but also easy to understand.
If this wasn't enough, note that the generic nature of the macros m1
and m2
enables us to write simple functions that take comma-separated parameters for anything in C++ that is inconvenient when time is of essence (overloaded operators).
Hope this was helpful!
PassionUnlimited
This blog was basically a copy-paste from this blog.
True, given that I wrote both blogs.
You should put a link to your blog in the CF blog so that other people can enjoy your blogs like I did. Keep it up!
Is there any way that modifies this code to initialize as well as cin the variable using m1(re) for some particular type of variable like int or string? like calling if we made m1 for int then it do
m1(a); ---->>> int a; cin>>a;
If yes then can anyone please provide its code?
Variant 1 (works starting with C++11, predefined variables):
Variant 2 (works starting with C++17, predefined variables):
Variant 3 — think of it as a joke (works starting with C++17, variables defined right there):
Con: you can't use read variables within lambda :(
Thanks a lot for reply, But unfortunately I was looking for something that can replace this code into any single command.
...and so on...
You can combine Variant 2 with variadic macros: