Hello, codeforces!
I would like to tell you about tips'n'tricks I use in C++ sources. Some of them require a strong C++ background, some not, but all of them are aimed to reduce the time you spend on basic things like reading input/debugging/etc, so it might be useful for your next template.
After a few hours of working on this post, I decided to split it into several more focused articles -- it's so hard to write about everything I planned, cover all nuances, and don't make it super-big.
For simple tasks, you may need to write very little code solving the problem and the biggest part of the source will be about reading values. Thus, declaring and reading variables seem like things that need to be simplified. Is there a way to shorten the following?
int n, m, k, t, q;
cin >> n >> m >> k >> t >> q;
There're a few ways, more or less flexible, I'll show one of them, you can find another, for example, here:
int READ(n, m, k, t, q);
// here variables n, m, k, t, q are declared and read from stdin.
In the following section we will use variadic number of arguments for functions and macros. It might be a bit hard to understand, but you still can copy/paste the result and skip this section.
How to achieve this? Well, we need to do two things: declare variables and read them. Let's start from scratch:
#define READ(...) __VA_ARGS__; read(__VA_ARGS__)
int READ(x, y, z);
// expands to:
int x, y, z; read(x, y, z);
Where read
is a function that reads all arguments given to it. But how to do it? We need a function that takes as many arguments as you want and reads every single one by reference from stdin. However, we can't simply iterate over them through a cycle:
for (auto &arg : args) cin >> arg;
We can't since there's no collection or smth else. But for simple and arguably short versions we could write the following:
void read() {}
template <class T>
void read(T &value) {
cin >> value;
}
template <class T1, class T2>
void read(T1 &x1, T2 &x2) {
cin >> x1 >> x2;
}
// and so on
It seems a little messy, isn't it? But what if we need to read 13 arguments and have a macro that works fine with only up to 10? Let's use variadic template parameters. We can use the simple trick with recursion: if there're parameters, take one of them, read it and repeat with the rest:
template <class ...Args>
void read(Args &...args);
template <>
void read() {}
template <class Arg, class ...Args>
void read(Arg &arg, Args &...args) {
cin >> arg;
read(args...);
}
Since C++17 we can do it slightly shorter and prettier with parameter pack:
template <class ...Args>
void read(Args &...args) {
(cin >> ... >> args);
}
Let's combine it all together:
template <class ...Args>
auto &read(Args &...args) { return (cin >> ... >> args); }
#define READ(...) __VA_ARGS__; read(__VA_ARGS__)
Note return type: it will be deduced as istream &
so you can read additional values:
vector<int> ws(m);
for (int e = 0; e < m; ++e) {
int READ(u, v) >> ws[e];
connect(--u, --v);
}
Types with no defined input operator, vector
To work with other types, you can define operator>>(istream &is, YourType &your_variable)
to use it with cin
or READ
macro. For example, you can define operator>>
for vector
. Often in problems, you need to read the size of a vector, followed by its elements. I could suggest using READ_CTOR
macro for this:
template <class T> istream &operator>>(istream &is, vector<T> &vec);
#define READ_CTOR(value, ...) value(__VA_ARGS__); cin >> value
// usage
int READ(n);
vector<int> READ_CTOR(xs, n);
READ_CTOR
can be used to initialize a variable with a constructor and then read it.
Example
You could look at all these tips in action here.
Credits
If you have any thoughts to extend or update this code, feel free to leave a comment below. What tricks do you use for reading values?
I would like to thank:
- viskonsin for help in editing this article
- Golovanov399 and HosseinYousefi for inspiring me to write this article (more will come)
- MikeMirzayanov for great Codeforces platform (haven't tried Polygon yet:)
- Whole codeforces community for sharing their great code -- it made me try to improve my template.
Auto comment: topic has been updated by dendi239 (previous revision, new revision, compare).
How would you do write instead of read?
You could simply use similar to
read
function:I am trying to compile your solution to 1367B using the following :
g++ -std=c++17 ToBeOrange.cpp
I am getting the following error :
Any ideas how should I fix this ?
Seems like you passed zero arguments to
read
function. Did you used smth likeREAD()
?I exactly copied the code from here (your submission to 1367B) :
https://codeforces.me/contest/1367/submission/84365686
Hmm, what compiler do you use?