Подтвердить что ты не робот

Печать любого контейнера STL

Как бы вы писали библиотеку, которая при включении перегружает оператор << для любого * существующего контейнера STL?

  • Кроме адаптеров, таких как стек и очередь, поскольку вы не можете их перебирать.

Одно из требований, предъявляемых к себе, состоит в том, что оно не должно содержать никаких файлов заголовков контейнеров. Это наполнило бы окончательный исполняемый файл излишне. Имеет смысл включить этот заголовок после контейнеров, с которыми я хотел бы работать. Это ограничение подразумевает использование templates или macros.

Я ищу советы и указатели, поэтому, пожалуйста, не просто публикуйте полностью рабочий код, который может это сделать! Реализация этого сама является частью процесса обучения. Небольшие фрагменты кода, которые демонстрируют, как некоторые вещи работают, приветствуются.

Что я сделал до этого момента:

Я перегрузил оператор << для каждого контейнера с другой подписью шаблона. Проблема, с которой я столкнулся с этим подходом, заключается в том, что существуют контейнеры с одинаковым количеством параметров шаблона, но некоторые содержат std::pair -s, другие single values. Точнее, это случай std::map и std::multimap vs std::unordered_set и std::unordered_multiset.

Это столкновение заставляет меня либо реализовать нетермическую версию одной из пар, либо создать способ различать std::pair -s и single values. Однако я действительно не знаю, как сделать вторую. Причина в том, что я не "как это сделать" напрямую, так это то, что я начинаю верить, что этого можно избежать полностью с лучшим общим дизайном.

Заранее благодарю!



Что сработало для меня:

  • Перегрузка operator<< для std::pair
  • Перегрузка operator<< для каждого контейнера STL с разными аргументами шаблона

    Примечание:

    • template <typename T1> и template <typename T1, typename T2> отличаются
    • template <typename T1, typename T2> и template <typename T1, size_t T2> являются отличается
    • template <typename T1, typename T2> и template <typename C1, typename C2>НЕ разные
  • Поместите их в пространство имен, чтобы убедиться, что ваши операторы не столкнутся с другими операциями, которые вам могут понадобиться в будущем.


Используйте "шаблоны в шаблонах", поэтому, например, функция будет выглядеть так:

template <typename Type, template <typename TYPE> class TClass>
void func(TClass<Type>& tc) {
    if (tc.somethingTrue())
        tc.doStuff();
}
4b9b3361

Ответ 1

Вы можете перегрузить operator<< в качестве шаблона, который принимает аргумент шаблона шаблона (т.е. любой контейнер).

Затем вы могли бы предоставить две перегрузки функции шаблона (например, print), чтобы одна перегрузка была специализирована на std::pair.

template<typename T>
std::ostream& print(std::ostream &out, T const &val) { 
  return (out << val << " ");
}

template<typename T1, typename T2>
std::ostream& print(std::ostream &out, std::pair<T1, T2> const &val) { 
  return (out << "{" << val.first << " " << val.second << "} ");
}

template<template<typename, typename...> class TT, typename... Args>
std::ostream& operator<<(std::ostream &out, TT<Args...> const &cont) {
  for(auto&& elem : cont) print(out, elem);
  return out;
}

LIVE DEMO

Ответ 2

Очень простая попытка решить эту проблему:

template<typename T>  
void print_container(std::ostream& os, const T& container, const std::string& delimiter)  
{  
    std::copy(std::begin(container),   
              std::end(container),   
              std::ostream_iterator<typename T::value_type>(os, delimiter.c_str())); 
}