Как определить тип объекта, на который указывает итератор в шаблонной функции c ++? - PullRequest
0 голосов
/ 25 июня 2018

У меня есть шаблонная функция в C ++, которая сериализует итерируемое:

template<typename Stream, typename Iter, typename Infix, typename Closure>
inline Stream &stream_iterable(Stream &os, Iter from, Iter to, Infix infix_, Closure open, Closure close) {
    if (from == to) return os;
    os << open << *from;
    for (++from; from != to; ++from) {
        os << infix_ << *from;
    }
    os << close;
    return os;
}

Для примера она в основном конвертирует std::vector<int>{1,2} в строку "[1,2]"

Я хотел бы проверитьтип объекта, на который указывает итератор, и если он равен std::string, я хотел бы использовать std::quoted для добавления кавычек вокруг элементов вектора, что-то вроде этого:

template<typename Stream, typename Iter, typename Infix, typename Closure>
inline Stream &steam_iterable_quoted(Stream &os, Iter from, Iter to, Infix infix_, Closure open, Closure close) {
    if (from == to) return os;
    os << open << std::quoted(*from);
    for (++from; from != to; ++from) {
        os << infix_ << std::quoted(*from);
    }
    os << close;
    return os;
}

Какможно проверить тип (* из) и объединить эти две функции в одну?

Ответы [ 4 ]

0 голосов
/ 25 июня 2018

Это самая простая, рабочая версия:

namespace quoting {
  template<class T>
  T const& auto_quote( T const& t ) { return t; }
  template<class C, class T>
  auto auto_quote( std::basic_string<C,T> const& s ) {
    return std::quoted(s);
  }
  // add more std types that need quoting here.
}

Теперь сделайте это:

// ...
if (from == to) return os;
using quoting::auto_quote;
os << open << auto_quote(*from);
for (++from; from != to; ++from) {
    os << infix_ << auto_quote(*from);
}
os << close;
// ...

для того, чтобы что-то было заключено в кавычки по-другому, переопределите auto_quote в пространстве имен типа (если не в std; нельзя вводить имена в std) или в namespace quoting. Он будет поднят автоматически.

Так что, если у вас есть my_string в пространстве имен my_ns:

namespace my_ns {
  auto auto_quote( my_string const& s ) {
    // some manual quoting code
  }
}

, и он будет автоматически выбран вышеуказанным кодом.

0 голосов
/ 25 июня 2018

На самом деле вам не нужно знать тип в теле stream_iterable. Как гласит старая поговорка, добавьте уровень косвенности:

namespace detail {
  template<typename T>
  constexpr T const& prepare_to_print(T const& t) { return t; }

  auto prepare_to_print(std::string const s&) { return std::quoted(s); }
  // A non-const overload would be required as well...
  // Forwarding can be a drag sometimes 
}

Просто передайте разыменованный итератор на prepare_to_print. Приятной особенностью перегрузок является то, что вы можете дополнительно настроить поведение, добавив больше из них позже.

0 голосов
/ 25 июня 2018

Вы можете использовать decltype(*from) для получения типа результата оператора разыменования, но (1) может потребоваться дальнейший массаж перед выполнением сравнений (это может быть ссылка, значение, возможно, cv-qualified, ...) и (2) это не очень расширяемый WRT других типов.

Как правило, для такого рода вещей вы хотите делегировать функцию шаблона, которая (в вашем случае) отвечает за фактический вывод данных в потоке, по умолчанию для "обычных" типов, и специализируетсяэто для типов, которые требуют особого отношения.

0 голосов
/ 25 июня 2018

Используйте это для получения типа объекта, на который ссылается итератор: std::iterator_triats<SomeIteratorType>::value_type

Чтобы объединить эти две функции, вы можете использовать оператор constexpr if, который является функцией C ++ 17.

...