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

Why compiler cannot deduce template template argument?

我想编写一个函数,它接受一个具有任何类型的通用容器并打印它。
暂且不谈它对某些关联容器不起作用,重点关注问题:

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);
}

错误状态:

error C2672: 'print': no matching overloaded function found    
error C3207: 'print': invalid template argument for 'Cont', class template expected

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

std::vector 不止一个 class-template-args.

template<
    class T,                // -----------> you have mentioned!
    class Allocator = std::allocator<T>  // -----> this didn't!
> class vector;

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

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

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;
}

(See a demo)


但是,您可以简单地做到这一点

template <typename Cont>
void print(const Cont& cont) 
{ 
   // ...
}

或者像标准方式一样,传递 the begin and end iterator of the container to the function

#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";
}

并称其为

print(v.begin(), v.end());

std::vector 定义为

template<
    class T,
    class Allocator = std::allocator<T>
> class vector;

std::vector 是具有两个模板参数的 class 模板。它不匹配 函数的模板模板参数。

改为

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

如果有必要,您可以从容器中推断出 T