Непонимание вариативных шаблонов и вывода типа шаблона
Я компилирую 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
такие же?
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
.