刷题debug的时候经常会需要打印stl容器里的元素,每次打印都要写一堆for循环,打印栈或者队列的时候还不能用for循环遍历,还要注意换行等等内容保证打印出来的东西自己能看懂,感觉很麻烦,于是写了一个类似python的可以直接打印出列表、元组、字典等所有元素print函数,编译参数加上C++17,源码如下:
/**
******************************************************************************
* @file : my_stl_print.h
* @author : Mr.Yi
* @brief : 简化打印stl容器中的数据
* @attention : None
* @date : 2023/4/30
******************************************************************************
*/
#pragma once
#include <iostream>
#include <vector>
#include <string>
#include <list>
#include <queue>
#include <deque>
#include <stack>
#include <set>
#include <unordered_set>
#include <map>
#include <unordered_map>
template <class T>
struct is_pair {
private:
template <class U, class V>
[[maybe_unused]] static std::true_type test(const std::pair<U,V> &) { return {}; }
static std::false_type test(...) { return {}; }
public:
static constexpr bool value = decltype(test(std::declval<T>()))::value;
};
template <class T>
struct is_vector {
private:
template <class U>
[[maybe_unused]] static std::true_type test(const std::vector<U> &) { return {}; }
static std::false_type test(...) { return {}; }
public:
static constexpr bool value = decltype(test(std::declval<T>()))::value;
};
template <class T>
struct is_list {
private:
template <class U>
[[maybe_unused]] static std::true_type test(const std::list<U> &) { return {}; }
static std::false_type test(...) { return {}; }
public:
static constexpr bool value = decltype(test(std::declval<T>()))::value;
};
template <class T>
struct is_deque {
private:
template <class U>
[[maybe_unused]] static std::true_type test(const std::deque<U> &) { return {}; }
static std::false_type test(...) { return {}; }
public:
static constexpr bool value = decltype(test(std::declval<T>()))::value;
};
template <class T>
struct is_queue {
private:
template <class U>
[[maybe_unused]] static std::true_type test(const std::queue<U> &) { return {}; }
static std::false_type test(...) { return {}; }
public:
static constexpr bool value = decltype(test(std::declval<T>()))::value;
};
template <class T>
struct is_priority_queue {
private:
template <class U>
[[maybe_unused]] static std::true_type test(const std::priority_queue<U> &) { return {}; }
template<class U, class Container, class Compare>
[[maybe_unused]] static std::true_type test(const std::priority_queue<U, Container, Compare> &) { return {}; }
static std::false_type test(...) { return {}; }
public:
static constexpr bool value = decltype(test(std::declval<T>()))::value;
};
template <class T>
struct is_stack {
private:
template <class U>
[[maybe_unused]] static std::true_type test(const std::stack<U> &) { return {}; }
static std::false_type test(...) { return {}; }
public:
static constexpr bool value = decltype(test(std::declval<T>()))::value;
};
template <class T>
struct is_set {
private:
template <class U, class V>
[[maybe_unused]] static std::true_type test(const std::set<U, V> &) { return {}; }
template <class U, class V>
[[maybe_unused]] static std::true_type test(const std::multiset<U, V> &) { return {}; }
template <class U, class V>
[[maybe_unused]] static std::true_type test(const std::unordered_set<U, V> &) { return {}; }
template <class U, class V>
[[maybe_unused]] static std::true_type test(const std::unordered_multiset<U, V> &) { return {}; }
static std::false_type test(...) { return {}; }
public:
static constexpr bool value = decltype(test(std::declval<T>()))::value;
};
template <class T>
struct is_map {
private:
template <class U, class V>
[[maybe_unused]] static std::true_type test(const std::map<U, V> &) { return {}; }
template <class U, class V>
[[maybe_unused]] static std::true_type test(const std::multimap<U, V> &) { return {}; }
template <class U, class V>
[[maybe_unused]] static std::true_type test(const std::unordered_map<U, V> &) { return {}; }
template <class U, class V>
[[maybe_unused]] static std::true_type test(const std::unordered_multimap<U, V> &) { return {}; }
static std::false_type test(...) { return {}; }
public:
static constexpr bool value = decltype(test(std::declval<T>()))::value;
};
template <class T>
inline constexpr bool is_pair_v = is_pair<T>::value;
template <class T>
inline constexpr bool is_vector_v = is_vector<T>::value;
template <class T>
inline constexpr bool is_list_v = is_list<T>::value;
template <class T>
inline constexpr bool is_deque_v = is_deque<T>::value;
template <class T>
inline constexpr bool is_queue_v = is_queue<T>::value;
template <class T>
inline constexpr bool is_priority_queue_v = is_priority_queue<T>::value;
template <class T>
inline constexpr bool is_stack_v = is_stack<T>::value;
template <class T>
inline constexpr bool is_set_v = is_set<T>::value;
template <class T>
inline constexpr bool is_map_v = is_map<T>::value;
template <class T>
inline constexpr bool is_stl_container = is_pair_v<T> || is_vector_v<T> || is_list_v<T> || is_deque_v<T> \
|| is_queue_v<T> || is_priority_queue_v<T> || is_stack_v<T> || is_set_v<T> || is_map_v<T>;
template <class T, size_t N>
void print(T (&arr)[N]) {
for (int i = 0; i < N; i++)
std::cout << arr[i] << " ";
std::cout << "\n";
}
template <class T, size_t M, size_t N>
void print(T (&arr)[M][N]) {
for (int i = 0; i < M; i++) {
for (int j = 0; j < N; j++)
std::cout << arr[i][j] << " ";
std::cout << "\n";
}
std::cout << "\n";
}
template <class T>
void print ([[maybe_unused]] const T& container) noexcept {
if constexpr(is_pair_v<decltype(container)>) {
std::cout << container.first << " " << container.second << "\n";
} else if constexpr (is_deque_v<decltype(container)> || is_vector_v<decltype(container)> \
|| is_list_v<decltype(container)> || is_set_v<decltype(container)>) {
for ([[maybe_unused]] const auto &value: container)
if constexpr (is_stl_container<decltype(value)>)
print(value);
else
std::cout << value << " ";
} else if constexpr (is_stack_v<decltype(container)> || is_priority_queue_v<decltype(container)>) {
auto tmp = container;
while (!tmp.empty()) {
[[maybe_unused]] auto top = tmp.top();
tmp.pop();
if constexpr (is_stl_container<decltype(top)>)
print(top);
else
std::cout << top << " ";
}
} else if constexpr (is_queue_v<decltype(container)>) {
auto tmp = container;
while (!tmp.empty()) {
[[maybe_unused]] auto front = tmp.front();
tmp.pop();
if constexpr (is_stl_container<decltype(front)>)
print(front);
else
std::cout << front << " ";
}
} else if constexpr (is_map_v<decltype(container)>) {
for ([[maybe_unused]] const auto& [v, k] : container) {
if constexpr (is_stl_container<decltype(k)>) {
std::cout << "v: " << v << " k: ";
print(k);
}
else
std::cout << "v: " << v << " k: " << k << "\n";
}
} else {
std::cout << container;
}
if constexpr (!is_pair_v<decltype(container)>)
std::cout << "\n";
}
测试代码如下,可简单验证元素顺序正确性:
namespace my_test_stl_print {
void test_vector () {
vector<int> v1 {1, 2, 3, 4, 5};
vector<string> v2 {"123", "234", "asd", "zxc"};
vector<vector<int>> v3 {{1,2,3},{4,5,6}, {7,8,9}};
vector<vector<string>> v4 {{"123", "234", "345"}, {"234", "345", "456"}};
vector<pair<int,int>> v5 {{1,2}, {2,3}, {3,4}};
vector<vector<vector<int>>> v6 {{{1,2,3} ,{4,5,6}}, {{7,8,9}, {10,11,12}}, {{13,14,15}} };
vector<list<int>> v7 {{1,2,3}, {4,5,6}};
vector<deque<int>> v8 {{1,2,3}, {4,5,6}};
vector<set<int>> v9 {{1,2,1,3}, {4,5,6,6}};
print(v1);
print(v2);
print(v3);
print(v4);
print(v5);
print(v6);
print(v7);
print(v8);
print(v9);
vector<vector<int>> v10;
for (int i = 0; i < 100; i++) {
vector<int> tmp;
for (int j = 0; j < 20; j++)
tmp.emplace_back(j);
v10.emplace_back(tmp);
}
print(v10);
}
void test_list () {
list<int> l1 {1, 2, 3, 4, 5};
list<string> l2 {"123", "234", "asd", "zxc"};
list<vector<int>> l3 {{1,2,3},{4,5,6}, {7,8,9}};
list<vector<string>> l4 {{"123", "234", "345"}, {"234", "345", "456"}};
list<pair<int,int>> l5 {{1,2}, {2,3}, {3,4}};
print(l1);
print(l2);
print(l3);
print(l4);
print(l5);
}
void test_deque () {
deque<int> d1{1, 2, 3, 4, 5};
deque<string> d2{"123", "234", "asd", "zxc"};
deque<vector<int>> d3{{1, 2, 3},
{4, 5, 6},
{7, 8, 9}};
deque<vector<string>> d4{{"123", "234", "345"},
{"234", "345", "456"}};
deque<pair<int, int>> d5{{1, 2},
{2, 3},
{3, 4}};
print(d1);
print(d2);
print(d3);
print(d4);
print(d5);
}
void test_queue () {
queue<int> q1;
q1.push(1);
q1.push(2);
q1.push(4);
q1.push(5);
print(q1);
print(q1);
queue<pair<int,int>> q2;
q2.push({2,3});
q2.push({3,4});
q2.push({5,7});
q2.push({9,9});
print(q2);
print(q2);
queue<string> q3;
q3.push("123");
q3.push("456");
q3.push("asd");
print(q3);
print(q3);
}
void test_stack () {
stack<int> stk1;
stk1.push(1);
stk1.push(2);
stk1.push(3);
stk1.push(4);
print(stk1);
print(stk1);
stack<pair<int,int>> stk2;
stk2.push({2,3});
stk2.push({3,4});
stk2.push({5,7});
stk2.push({9,9});
print(stk2);
print(stk2);
stack<string> stk3;
stk3.push("123");
stk3.push("456");
stk3.push("asd");
print(stk3);
print(stk3);
}
void test_priority_queue () {
priority_queue<int, vector<int>, greater<>> pq1;
pq1.push(1);
pq1.push(2);
pq1.push(4);
pq1.push(5);
print(pq1);
print(pq1);
priority_queue<pair<int,int>> pq2;
pq2.push({2,3});
pq2.push({3,4});
pq2.push({5,7});
pq2.push({9,9});
print(pq2);
priority_queue<string> pq3;
pq3.push("123");
pq3.push("456");
pq3.push("asdc");
print(pq3);
print(pq3);
}
void test_set () {
set<int> s1 {1,1,2,2,3,3,4,4};
set<pair<int,int>> s2 {{1,2},{2,3},{3,4},{1,2}};
multiset<int> s3 {1,1,2,2,3,3,4,4};
unordered_set<int> s4 {1,1,2,2,3,3,4,4};
unordered_multiset<int> s5 {1,1,1,2,3,4,5,6};
print(s1);
print(s2);
print(s3);
print(s4);
print(s5);
}
void test_map () {
map<int,int> mp1 {{1,2},{2,3},{3,4}};
map<string,string> mp2 {{"ad","da"}, {"cd", "sx"}};
map<int, pair<int,int>> mp3 {{1, {2,3}}, {2, {3,3}}};
map<int, vector<int>> mp4 {{1, {2,3}}, {3, {2,3}}};
map<int, stack<int>> mp5;
mp5[1].push(1);
mp5[5].push(2);
unordered_map<int, map<int,int>> mp6;
mp6[1] = mp1;
mp6[1000] = mp1;
print(mp1);
print(mp2);
print(mp3);
print(mp4);
print(mp5);
print(mp6);
}
void test() {
test_vector();
test_list();
test_deque();
test_queue();
test_stack();
test_priority_queue();
test_set();
test_map();
}
}