Непонимание вариативных шаблонов и вывод типа шаблона

Я компилирую C++17 с кодом, подобным этому образцу:

#include <iostream>
#include <iterator>

class Foo {};

template <typename... Args,
  typename ostream_type = ::std::basic_ostream<Args...>,
  typename ostreambuf_iterator_type = ::std::ostreambuf_iterator<Args...>>
ostream_type &operator<<(ostream_type &os, const ::Foo f) {
  // Do ostreambuf_iterator_type stuff with 'f' here...
  return os;
}

int main() {
  ::Foo f;
  ::std::cout << f;

  return 0;

}

Я обнаружил, что вывод типа шаблона терпит неудачу, когда я применяю Args... к списку параметров шаблона как ostream_type, так и ostreambuf_iterator_type, но было бы хорошо, если бы я назначил char_type и traits_type из ostream_type.

typename ostreambuf_iterator_type = ::std::ostreambuf_iterator<typename ostream_type::char_type, typename ostream_type::traits_type>>

Почему так, когда параметры шаблона на ::std::basic_ostream и ::std::ostreambuf_iterator одинаковы?


person Matthew Reddington    schedule 21.10.2019    source источник
comment
С тех пор я понял, что могу избежать большего вывода в теле функции, мне не нужно указывать параметры итератора, но этот код все еще вызывает вопрос, почему Args... не работает, как я ожидал.   -  person Matthew Reddington    schedule 22.10.2019


Ответы (1)


Вывод аргумента шаблона пытается вывести ostream_type из аргумента функции. При этом он не связан предоставленным вами аргументом по умолчанию. Вместо этого аргумент по умолчанию просто игнорируется.

ostream_type будет преобразовано в std::basic_ostream<char>.

Тогда ничего не остается в зависимости от Args в параметрах функции и пакет параметров выводится как пустой.

Затем пустой Args расширяется до аргумента по умолчанию ostreambuf_iterator_type = ::std::ostreambuf_iterator<Args...>, что не удается, поскольку std::ostreambuf_iterator требуется хотя бы один аргумент шаблона.

Если вы хотите, чтобы Args выводилось как аргументы шаблона для std::basic_ofstream, переданного вашей функции, вам необходимо ограничить вывод аргумента шаблона в параметре:

template <typename... Args,
  typename ostreambuf_iterator_type = ::std::ostreambuf_iterator<Args...>>
auto &operator<<(::std::basic_ostream<Args...> &os, const Foo f) {
  // Do ostreambuf_iterator_type stuff with 'f' here...
  return os;
}

Теперь дедукция должна вывести Args в качестве аргументов шаблона os.

person walnut    schedule 21.10.2019