对可变参数模板和模板类型推导的误解

Misunderstanding variadic templates and template type deduction

我正在使用 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_typeostreambuf_iterator_type的模板参数列表时模板类型推导失败,但如果我赋值就没问题来自 ostream_type.

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

为什么 ::std::basic_ostream::std::ostreambuf_iterator 的模板参数相同?

模板参数推导试图从函数参数推导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 的模板参数。