Skip to content

Instantly share code, notes, and snippets.

@haseeb-heaven
Last active July 2, 2025 12:07
Show Gist options
  • Save haseeb-heaven/79e46651347155be7ae7e55a57da91c0 to your computer and use it in GitHub Desktop.
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.
/*
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;
}
@haseeb-heaven
Copy link
Author

haseeb-heaven commented Jun 16, 2022

#include "printc.hpp" // Include the printing utility library
#include <vector>
#include <map>
#include <iostream>
#include <string>

int main() {
    // Example 1: Using printc() with a vector
    std::vector<int> integerVector = {1, 2, 3};
    std::cout << "Using printc() for vector:\n";
    printc(integerVector);

    // Example 2: Using << operator with a map
    std::map<std::string, int> fruitQuantities = {
        {"Apple", 5},
        {"Banana", 8}
    };
    std::cout << "\nUsing << operator for map:\n";
    std::cout << fruitQuantities;

    return 0;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment