为什么编译器不能推导出模板模板参数?

Edu*_*yan 2 c++ templates template-templates function-templates c++11

我想编写一个函数,该函数采用任何类型的通用容器并打印它。
让我们暂时搁置它不适用于某些关联容器并关注这个问题:

template<template<typename> typename Cont, typename T>
void print(const Cont<T>& cont)
{
   for (const auto it : cont)
   {
      cout << it << " ";
   }
   cout << endl;
}

int main()
{
   vector<string> v;
   print(v);
}
Run Code Online (Sandbox Code Playgroud)

错误指出:

template<template<typename> typename Cont, typename T>
void print(const Cont<T>& cont)
{
   for (const auto it : cont)
   {
      cout << it << " ";
   }
   cout << endl;
}

int main()
{
   vector<string> v;
   print(v);
}
Run Code Online (Sandbox Code Playgroud)

谁能解释为什么编译器不能在这里推断出类型?
即使我明确声明print<vector<string>>(v)

JeJ*_*eJo 5

std::vector 有不止一个类模板参数。

template<
    class T,                // -----------> you have mentioned!
    class Allocator = std::allocator<T>  // -----> this didn't!
> class vector;
Run Code Online (Sandbox Code Playgroud)

但是你只提供了一个。这就是没有匹配的重载编译器错误的原因。

为了解决这个问题,您需要在模板模板 arg 中提供可变参数 args。

template<template<typename...> typename Cont, typename T>
//       ^^^^^^^^^^^^^^^^^^^^
void print(const Cont<T>& cont)
{
   for (const auto& it : cont) {
      std::cout << it << " ";
   }
   std::cout << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

见演示


但是,您可以简单地完成此操作

template <typename Cont>
void print(const Cont& cont) 
{ 
   // ...
}
Run Code Online (Sandbox Code Playgroud)

或者像标准方式一样,将容器的开始和结束迭代器传递给函数

#include <algorithm>  // std::copy
#include <iterator>   // std::iterator_traits

template<typename Iterator>
constexpr void print(const Iterator begin, const Iterator end) noexcept
{
   using ValueType = typename std::iterator_traits<Iterator>::value_type;
   std::copy(begin, end, std::ostream_iterator<ValueType>(std::cout, " "));
   std::cout << "\n";
}
Run Code Online (Sandbox Code Playgroud)

并称之为

print(v.begin(), v.end());
Run Code Online (Sandbox Code Playgroud)

  • 或者完全删除模板模板参数,并将其设为“template &lt;typename Cont&gt; void print(const Cont&amp; cont) {...}” (2认同)