I Made a C++ Version of Python print() Function
Tags: cpp, competativeprogramming, programming, python
Published: 2023-10-09 14:46:33

I like Python's `print(obj...)` since it can print variables of any type: numbers, strings, arrays, and objects, and is helpful for debugging.
I have been doing competitive programming recently, but the function helps me debug there, too.

But C++ doesn't have a function like this.
C++ is fast and suited for competitive programming, but every time you want to print a vector for debugging, you have to write a long code like `for(int i = 0; i < N; ++i) std::cout << a[i] << std::endl;`. Competitive programming is a race against time, so I want to avoid that.

Then why not make a C++ version of `print(obj...)` myself? 
So I made one (with much effort)!

## Table of Contents
&nbsp;1. [Let's try it first!](#lets-try-it-first)
&nbsp;2. [How to Use?](#how-to-use)
&nbsp;3. [7 (or more) Features of the cpp-dump Library](#7-or-more-features-of-the-cppdump-library)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.1. [1. Python-Like String Representation](#1-pythonlike-string-representation)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.2. [2. Auto Indent](#2-auto-indent)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.3. [3. Filename and line Can Be Printed Instead of [dump]](#3-filename-and-line-can-be-printed-instead-of-raw-dump-endraw-)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.4. [4. A Wide Range of Other Supported Types](#4-a-wide-range-of-other-supported-types)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.5. [5. User Types Can Also Be Printed](#5-user-types-can-also-be-printed)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.6. [6. Customizable Output Colors](#6-customizable-output-colors)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.7. [7-. Other Customizable and Useful Features](#7-other-customizable-and-useful-features)

&nbsp;4. [For Competitive Programming Use](#for-competitive-programming-use)
&nbsp;5. [Conclusion](#conclusion)

## Let's try it first!
{% github philip82148/cpp-dump %}
First, let's run this command in the terminal.
(If you can't use the `git` command, download and unzip the source folder in [Releases](https://github.com/philip82148/cpp-dump/releases) instead.)
```shell
git clone https://github.com/philip82148/cpp-dump
```
Next, let's copy and paste this code and run it.
```cpp
#include <bitset>
#include <complex>
#include <map>
#include <optional>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <utility>
#include <variant>
#include <vector>

#include "./cpp-dump/dump.hpp"

int main() {
  int my_int = 15;
  int *ptr = &my_int;
  void *void_ptr = &my_int;
  std::vector<std::vector<int>> my_vector{{3, 5, 8, 9, 7}, {9, 3, 2, 3, 8}};
  std::set<char> my_set{'A', 'p', 'p', 'l', 'e'};
  std::map<int, int> my_map{{2, 6}, {4, 6}, {5, 3}};
  std::multiset<char> my_multiset{'A', 'p', 'p', 'l', 'e'};
  std::multimap<int, int> my_multimap{{2, 4}, {4, 6}, {5, 3}, {4, 7}};
  std::pair<int, char> my_pair{8, 'a'};
  std::tuple<int, double, std::string> my_tuple{7, 4.5, "This is a string."};
  std::queue<int> my_queue;
  std::priority_queue<int> my_priority_queue;
  std::stack<int> my_stack;
  for (auto v : {1, 2, 3, 4, 5}) my_queue.push(v), my_priority_queue.push(v), my_stack.push(v);
  std::bitset<8> my_bitset(0x3a);
  std::complex<double> my_complex{1.0, 1.0};
  std::optional<int> my_optional{15};
  std::variant<int, std::string> my_variant{"1"};
  std::vector<std::pair<int, std::string>> vector_of_pairs{{1, "apple"}, {3, "banana"}};

  std::clog << "\n// Basic Type" << std::endl;
  cpp_dump(false, 0, 0.0, '0'), cpp_dump(true, 3.14, my_int, 9265);
  cpp_dump("This is a string."), cpp_dump(ptr, void_ptr, nullptr);

  std::clog << "\n// Container" << std::endl;
  cpp_dump(my_vector);

  std::clog << "\n// Set/Map" << std::endl;
  cpp_dump(my_set), cpp_dump(my_map);

  std::clog << "\n// Multiset/Multimap" << std::endl;
  cpp_dump(my_multiset), cpp_dump(my_multimap);

  std::clog << "\n// Tuple" << std::endl;
  cpp_dump(my_tuple), cpp_dump(my_pair);

  std::clog << "\n// FIFO/LIFO" << std::endl;
  cpp_dump(my_queue), cpp_dump(my_priority_queue), cpp_dump(my_stack);

  std::clog << "\n// Other" << std::endl;
  cpp_dump(my_bitset), cpp_dump(my_complex);
  cpp_dump(my_optional, std::nullopt), cpp_dump(my_variant);

  std::clog << "\n// Combination" << std::endl;
  cpp_dump(vector_of_pairs);

  std::clog << std::endl;
}
```
Then, the output will be like this!
![https://github.com/philip82148/cpp-dump/raw/main/readme/supports-various-types.png](https://github.com/philip82148/cpp-dump/raw/main/readme/supports-various-types.png?3)

## How to Use?
You can print various variables by passing them to the `cpp_dump(exprs...)` macro!

Code:
```cpp
// In main() or some function
std::vector<std::vector<int>> my_vector{{3, 5, 8, 9, 7}, {9, 3, 2, 3, 8}};
cpp_dump(my_vector);
```
Output:
![Output Example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r0rznv28quveev1253q1.png)

## 7 (or more) Features of the cpp-dump Library
### 1. Python-Like String Representation
Like Python's `print()`, cpp-dump prints variables in a **Python-like string representation**.

#### Output of Iterables Like std::vector, std::array, C-style arrays:
![Output Example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4blhx04j0j14szxycxx1.png)
#### Output of std::map and std::unordered_map:
![Output Example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/knf0xx39li4jhn9dq3pt.png)
#### Output of std::tuple and std::pair:
![Output Example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7nsp7uvl010s1tmmzl1b.png)
#### Output of std::set and std::unordered_set:
![Output Example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h6kpzgg8febzxg99wtw0.png)

### 2. Auto Indent
If the content of a variable is large, cpp-dump **automatically indents** so that the output fits into the maximum line width.
#### Output of Iterables Like std::vector, std::array, C-style arrays:
![Output Example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qtv3l8b1si5qp4lmztff.png)The output of std::tuple, std::pair, std::set, and std::unordered_set is also indented in the same way.
#### Output of std::map and std::unordered_map:
![Output Example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zam1qea3fidz7pasyqzw.png)

### 3. Filename and line Can Be Printed Instead of `[dump]`
You can print **the filename and the line** instead of `[dump]`, by using the following code.

```cpp
CPP_DUMP_SET_OPTION(log_label_func, cp::log_label::filename());
```

![customize dump](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fs3m1tinb6qjt5wuflp5.png)

### 4. A Wide Range of Other Supported Types
cpp-dump supports **various other types** like std::multimap, std::queue, std::complex, etc!
See the [README](https://github.com/philip82148/cpp-dump#supported-types) in the repo for all supported types.

![https://github.com/philip82148/cpp-dump/raw/main/readme/supports-various-types.png](https://github.com/philip82148/cpp-dump/raw/main/readme/supports-various-types.png)

### 5. User Types Can Also Be Printed
By using macros or defining operators, you can enable cpp-dump to print **user-defined types!**
See the [README](https://github.com/philip82148/cpp-dump#can-print-even-user-defined-types) in the repo for details.

```cpp
CPP_DUMP_DEFINE_DANGEROUS_EXPORT_OBJECT(i, str());
```

![user-defined](https://github.com/philip82148/cpp-dump/raw/main/readme/user-defined-class2.png)

### 6. Customizable Output Colors
You can customize the colors of the output of cpp-dump!
The following image is an example.
See the [README](https://github.com/philip82148/cpp-dump#customizable-output-colors) in the repo for details.
![https://github.com/philip82148/cpp-dump/raw/main/readme/customizable-colors.png](https://github.com/philip82148/cpp-dump/raw/main/readme/customizable-colors.png?2)

### 7-. Other Customizable and Useful Features
In addition to the features above, there are some other customizable and useful features; for example, there are manipulators that change the display method!
See the [README](https://github.com/philip82148/cpp-dump?tab=readme-ov-file#manipulators-to-change-the-display-style) in the repo for details.

#### Manipulator to set which and how many elements of an array will be displayed
![manipulators.png](https://github.com/philip82148/cpp-dump/raw/main/readme/manipulators.png?2)
#### Manipulator to change the base of integers
![int-style.png](https://github.com/philip82148/cpp-dump/raw/main/readme/int-style.png?2)
#### Manipulator to display array indices
![cont-index](https://github.com/philip82148/cpp-dump/raw/main/readme/cont-index.png?2)

## For Competitive Programming Use
`cpp_dump(vars...)` is long, so let's shorten it to `dump(vars...)` by macro.
Also, let's write like the following to remove `dump(vars...)` when submitting the code.
```cpp
#ifdef DEFINED_ONLY_IN_LOCAL
#include "./cpp-dump/dump.hpp"
#define dump(...) cpp_dump(__VA_ARGS__)
namespace cp = cpp_dump;
#else
#define dump(...)
#define CPP_DUMP_SET_OPTION(...)
#define CPP_DUMP_DEFINE_EXPORT_OBJECT(...)
#define CPP_DUMP_DEFINE_EXPORT_ENUM(...)
#define CPP_DUMP_DEFINE_DANGEROUS_EXPORT_OBJECT(...)
#endif

#include <bits/stdc++.h>

#define rep(i, n) for (int i = 0; i < (int)(n); ++i)

using namespace std;

int main() {
  CPP_DUMP_SET_OPTION(max_line_width, 80);
  CPP_DUMP_SET_OPTION(log_label_func, cp::log_label::filename());
  CPP_DUMP_SET_OPTION(enable_asterisk, true);

  int N;
  cin >> N;

  vector<int> X(N);
  rep(i, N) { cin >> X[i]; }
  dump(X);

  // To be continued...
}
```
Then, when compiling the source locally, the `dump()` macro will only work locally by running the following command!
```shell
g++ ./main.cpp -D DEFINED_ONLY_IN_LOCAL
```

## Conclusion
I hope this library helps.
And don't forget to give it a GitHub star!