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

时间:2019-10-21 22:33:14

标签: c++ variadic-templates variadic-functions template-argument-deduction 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的模板参数列表时,我发现模板类型推导失败,但是如果我分配了{ {1}中的{1}}和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的模板参数相同?

1 个答案:

答案 0 :(得分:3)

模板自变量推导尝试从函数自变量推导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的模板参数。