Many times while debugging in contests, to trace the elements I use multiple functions like following,
It's good if I can trace all using one method, I was looking for one single function/method for printing variables, vectors, etc.
Watching Errichto streams and this tweet during ICPC live stream, I got interested in this template but couldn't understand much of this, I wanted to use this template, know how to use, but don't understand why it works, and I try not to put things that I don’t understand in my template, Can you please help me in understanding this
We can generally use this like this
debug() << imie(c * 2) imie(min(a, b)) imie(a != b);
debug() << "add" imie(i) imie(A) imie(diff);
debug() << imie(V); // V is a vector
debug() << imie(a) imie(h1) imie(h2) imie(my_dist) imie(path) imie(vertices); // int a,h1,h2; vector path;
debug() << "Zlaczacz::Ogarnij(" imie(a) imie(b) ") = " << res; // pair<vector<int>, vector<int>> res; int a,b;
So I have elaborated code and it resulted in the following
#define sim template < class c
#define ris return * this
#define dor > debug & operator <<
#define eni(x) sim > typename \
enable_if<sizeof dud<c>(0) x 1, debug&>::type operator<<(c i) {
/*sim > struct rge { c b, e; };
sim > rge<c> range(c i, c j) { return rge<c>{i, j}; }
sim > auto dud(c* x) -> decltype(cerr << *x, 0);
sim > char dud(...);*/
template < class c > struct rge { c b, e; };
template < class c > rge<c> range(c i, c j) { return rge<c>{i, j}; }
template < class c > auto dud(c* x) -> decltype(cerr << *x, 0);
template < class c > char dud(...);
struct debug {
~debug() { cerr << endl; }
//eni(!=) cerr << boolalpha << i; ris; } Part 1
template < class c > typename \
enable_if<sizeof dud<c>(0) != 1, debug&>::type operator<<(c i) {
cerr << boolalpha << i;
return * this;
}
//eni(==) ris << range(begin(i), end(i)); } Part 2
template < class c > typename \
enable_if<sizeof dud<c>(0) == 1, debug&>::type operator<<(c i) {
return * this << range(begin(i), end(i));
}
/*sim, class b dor(pair < b, c > d) { Part 3
ris << "(" << d.first << ", " << d.second << ")";
}*/
template < class c, class b > debug & operator << (pair < b, c > d) {
return * this << "(" << d.first << ", " << d.second << ")";
}
/*sim dor(rge<c> d) { Part 4
*this << "[";
for (auto it = d.b; it != d.e; ++it)
*this << ", " + 2 * (it == d.b) << *it;
ris << "]";
}*/
template < class c > debug & operator <<(rge<c> d) {
*this << "[";
for (auto it = d.b; it != d.e; ++it)
*this << ", " + 2 * (it == d.b) << *it;
return * this << "]";
}
}
#define imie(...) " [" << #__VA_ARGS__ ": " << (__VA_ARGS__) << "] "
std::boolalpha
is an I/O manipulator, it causes bool values to display as true or false. decltype
inspects the declared type of an entity or the type and value category of expression.
When the macro is invoked, all the tokens in its argument list after the last named argument (this macro has none), including any commas, become the variable argument. This sequence of tokens replaces the identifier __VA_ARGS__
in the macro body wherever it appears. You may use the #
and ##
operators to stringify the variable argument or to paste its leading or trailing token with another token — Ref
template< bool B, class T = void >
struct enable_if;
/* If B is true, std::enable_if has a public member typedef type, equal to T; otherwise, there is no member typedef. */
template <typename T>
struct enable_if<true, T> {
typedef T type;
};
Can someone please explain what eni(x)
, dud
does? and how does eni
relate to Part 1 and Part 2? I didn't understand eni(x)
and dud
.
How rge
is used in range
?
I understand that Part 4 is to iterate through containers, is Part 3 for pairs?
Thank you in advance.
You don't have to write
imie
everywhere. It's just thatimie
changes a variable into its name and value. Plus it's a class so you can create it, print some things, and then a newline character will be printed in the destructor.range
allows printing arrays. Trydebug() << range(a, a+n)
ordebug() << imie(range(a, a+n))
.yes
Summoning mareksom in case of more questions, and tnowak because maybe he would like to explain his shorter/improved templates.
Which flags do we have to use locally to compile the code in the given template?
These are flags which Errichto uses
g++ -std=c++17 -Wshadow -Wall -o a a.cpp -fsanitize=address -fsanitize=undefined -D_GLIBCXX_DEBUG -g
The gcc option -DNAME defines a preprocessor macro NAME from the command line.
So you should use
-DLOCAL
eni(x)
anddud
are sfinae tricks to specify when to use which function (which operator<<). The "part 1" tells the compiler to use this operator<< for any objects that can use cout, and "part 2" for other objects — it assumes they are containers with iterators.rge
stores those begin/end iterators, and the "part 4" prints the container.*this << ", " + 2 * (it == d.b) << *it;
play role in excluding ',' at start of printing?decltype(cerr << *x, 0);
doing? What will besizeof dud<c>(0)
when we pass different objects to print? What is the role of 0 indecltype(cerr << *x, 0);
?I have the following:
Basically for printable objects, we have other than 1, But can't understand how
dud
is returning those values usingdud(c* x) -> decltype(cerr << *x, 0);
?Any help would be greatly appreciated.
Don't analyze so hacky code if you don't know C++ well.
cout << "abcd" + x
prints "abcd" starting from x-th character.a, b
runsa
and then runsb
and returns its value.And I won't answer all your questions because I don't understand our templates. mareksom does.
There is a warning if we use
"abcd" + x
To fix this, I've changed
*this << ", " + 2 * (it == d.b) << *it;
to*this << string(", ").substr(2 * (it == d.b)) << *it;
Or just use
-Wno-string-plus-int
flag while compilingDo you have any suggestions?
Ternary operator should be better, I think.
The first line is a function template declaration (there is no definition), which takes as an argument a pointer to any type
c
and returns an integer (decltype(0)
isint
, sodecltype(anything at all, 0)
isint
).The second line is a function template declaration (again, there is no definition), which takes any number of arguments of any type (like
printf
) and returns a character (char
).When you write
dud<c>
, the compiler will try to resolve this template to one of these two functions, based on the typec
. The "ellipsis thing" has the lowest priority when it comes to resolving template functions. So, if the first declaration is well-formed, then it will be chosen, and if not, then the second declaration will be chosen. Thecerr << *x
part is responsible for this resolution: the first template with typec
is well-formed if and only if the typec
can be printed tocerr
. To better understand the details, you should read about SFINAE.When you write
sizeof dud<c>(0)
(or bettersizeof dud<c>(nullptr)
), you get a size of1
ifdud<c>
returns characters, or a size greater than1
(usually4
) ifdud<c>
returns integers. So, you get1
if objects of typec
cannot be printed tocerr
or something greater than1
if objects of typec
can be printed tocerr
.The function
dud<c>
takes as an argument a pointer to typec
, not an object of typec
, so that you can easily call it this way:dud<c>(nullptr)
ordud<c>(0)
. If you had to pass an object, you would need to call a constructor and assume that this constructor exists and is public.Thank you very much.
To add:-
The operands of the operators
typeid
,sizeof
,noexcept
, anddecltype
(since C++11) are expressions that are not evaluated since these operators only query the compile-time properties of their operands.The sizeof operator permits us to returns the size in bytes of a type or an expression at compilation time.
sizeof
operator does a "fake evaluation" of the expression that you pass to it.SFINAE on the return type, where the expression uses the comma operator, whose left subexpression is the one that is being examined (cast to void to ensure the user-defined operator comma on the returned type is not selected), and the right subexpression has the type that the function is supposed to return.
Reference