PassionUnlimited's blog

By PassionUnlimited, 2 months ago, In English

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

 
 
 
 
  • Vote: I like it
  • +31
  • Vote: I do not like it

»
2 months ago, # |
  Vote: I like it +5 Vote: I do not like it

This blog was basically a copy-paste from this blog.

  • »
    »
    2 months ago, # ^ |
      Vote: I like it +22 Vote: I do not like it

    True, given that I wrote both blogs.

    • »
      »
      »
      2 months ago, # ^ |
        Vote: I like it 0 Vote: I do not like it

      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!