Last active
July 2, 2025 12:07
-
-
Save haseeb-heaven/79e46651347155be7ae7e55a57da91c0 to your computer and use it in GitHub Desktop.
C++ General way of printing data of container including List,Sets,Maps,Stack,Queues etc.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Info: C++ General way of printing data of container including List, Sets, Maps, Stack, Queues, etc. | |
From this library, we have two ways to print supported STL containers: | |
* 1. Use the printc(container) function | |
* 2. Use the overloaded << operator with std::cout | |
Author: Haseeb Mir @2022. | |
*/ | |
#pragma once | |
#include <iostream> | |
#include <map> | |
#include <set> | |
#include <list> | |
#include <vector> | |
#include <deque> | |
#include <queue> | |
#include <stack> | |
#include <string> | |
#include <type_traits> | |
#include <utility> | |
#include <iterator> | |
/** | |
* @brief Trait to check if a container is map-like (std::map or std::multimap). | |
*/ | |
template <typename T> | |
struct is_map : std::false_type {}; | |
template <typename KeyType, typename ValueType> | |
struct is_map<std::map<KeyType, ValueType>> : std::true_type {}; | |
template <typename KeyType, typename ValueType> | |
struct is_map<std::multimap<KeyType, ValueType>> : std::true_type {}; | |
/** | |
* @brief Trait to check if a container is a std::stack. | |
*/ | |
template <typename T> | |
struct is_stack : std::false_type {}; | |
template <typename ElementType> | |
struct is_stack<std::stack<ElementType>> : std::true_type {}; | |
/** | |
* @brief Trait to check if a container is a std::queue. | |
*/ | |
template <typename T> | |
struct is_queue : std::false_type {}; | |
template <typename ElementType> | |
struct is_queue<std::queue<ElementType>> : std::true_type {}; | |
/** | |
* @brief Trait to detect if T has begin() and end() (i.e. is iterable). | |
*/ | |
template <typename T, typename = void> | |
struct has_begin_end : std::false_type {}; | |
template <typename T> | |
struct has_begin_end<T, std::void_t< | |
decltype(std::declval<T>().begin()), | |
decltype(std::declval<T>().end()) | |
>> : std::true_type {}; | |
/** | |
* @brief Prints the contents of a supported STL container to std::cout. | |
* | |
* Supports: | |
* - map-like: std::map, std::multimap | |
* - adapters: std::stack, std::queue | |
* - general iterables: vector, list, set, deque, etc. | |
* | |
* @tparam ContainerType The container type. | |
* @param container The container to print. | |
* @param delimiter Delimiter between elements (default: tab). | |
*/ | |
template <typename ContainerType> | |
void printc( | |
const ContainerType& container, | |
const std::string& delimiter = "\t" | |
) { | |
if (container.empty()) { | |
std::cout << "Container is empty." << std::endl; | |
return; | |
} | |
if constexpr (is_map<ContainerType>::value) { | |
// map or multimap: key<del>value per line | |
for (const auto& [key, value] : container) { | |
std::cout << key << delimiter << value << std::endl; | |
} | |
} | |
else if constexpr (is_stack<ContainerType>::value || | |
is_queue<ContainerType>::value) | |
{ | |
// stack or queue: copy & pop | |
ContainerType copy = container; | |
while (!copy.empty()) { | |
if constexpr (is_stack<ContainerType>::value) | |
std::cout << copy.top(); | |
else | |
std::cout << copy.front(); | |
std::cout << delimiter; | |
copy.pop(); | |
} | |
std::cout << std::endl; | |
} | |
else { | |
// general iterable | |
for (const auto& element : container) { | |
std::cout << element << delimiter; | |
} | |
std::cout << std::endl; | |
} | |
} | |
/** | |
* @brief Stream-insertion overload for supported STL containers. | |
* | |
* Enables: | |
* std::cout << vec; | |
* std::cout << myMap; | |
* std::cout << myStack; | |
* | |
* Excludes: | |
* std::string and C-strings (to avoid ambiguity). | |
* | |
* @tparam ContainerType The container type. | |
* @param os The output stream. | |
* @param container The container to print. | |
* @return std::ostream& The updated stream. | |
*/ | |
template < | |
typename ContainerType, | |
// exclude std::string | |
typename = std::enable_if_t<!std::is_same_v<ContainerType, std::string>>, | |
// exclude C-strings | |
typename = std::enable_if_t<!std::is_convertible_v<ContainerType, const char*>>, | |
// enable only for map-like, adapters, or iterables | |
typename = std::enable_if_t< | |
is_map<ContainerType>::value || | |
is_stack<ContainerType>::value || | |
is_queue<ContainerType>::value || | |
has_begin_end<ContainerType>::value | |
> | |
> | |
std::ostream& operator<<(std::ostream& os, const ContainerType& container) { | |
if (container.empty()) { | |
os << "Container is empty." << std::endl; | |
return os; | |
} | |
if constexpr (is_map<ContainerType>::value) { | |
for (const auto& [key, value] : container) { | |
os << key << "\t" << value << std::endl; | |
} | |
} | |
else if constexpr (is_stack<ContainerType>::value || | |
is_queue<ContainerType>::value) | |
{ | |
ContainerType copy = container; | |
while (!copy.empty()) { | |
if constexpr (is_stack<ContainerType>::value) | |
os << copy.top(); | |
else | |
os << copy.front(); | |
os << "\t"; | |
copy.pop(); | |
} | |
os << std::endl; | |
} | |
else { | |
for (const auto& element : container) { | |
os << element << "\t"; | |
} | |
os << std::endl; | |
} | |
return os; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.