嵌套模板函数的重载

Edu*_*yan 2 c++ templates overloading language-lawyer c++11

我一直在想给我的问题取什么标题,但还是失败了,所以如果你找到一个好的,请编辑它。

我正在尝试为 avector或 other编写一个打印函数,container<T>并为 编写另一个打印函数container<container<T>>,所以这里我想出了:

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

template<typename T, template<typename> typename Cont>
void print(Cont<T> const& cont) {
    for (const auto& i : cont) {
        print(i);
    }
}
Run Code Online (Sandbox Code Playgroud)

我在这里有我的 2 个目标容器:

vector<vector<int>> subsets;
vector<int> subset;
Run Code Online (Sandbox Code Playgroud)

当我调用print(subset);程序时按预期工作,但是当我调用时print(subsets),编译器开始抱怨:

error C2679: binary '<<': no operator found which takes a right-hand operand of type 'const std::vector<int,std::allocator<int>>' (or there is no acceptable conversion)
Run Code Online (Sandbox Code Playgroud)

我的结论是,它仍在尝试调用非嵌套模板打印函数,但在cout我尝试计算向量时失败。

谁能解释为什么重载决议没有按我的预期工作以及我在这里做错了什么?即使我将嵌套模板函数重命名为 printn,它也会因为不同的原因开始抱怨:

error C2784: 'void prints(const Cont<T> &)': could not deduce template argument for 'const Cont<T> &' from 'std::vector<std::vector<int,std::allocator<int>>,std::allocator<std::vector<int,std::allocator<int>>>>'
Run Code Online (Sandbox Code Playgroud)

Yak*_*ont 5

简短、简单且不充分的答案是std::vector有 2 个模板参数。您还应该包括一些间距:

template<class T, class A, template<class, class>class C>
void print(C<T,A> const& cont) {
  std::cout << "[ ";
  bool bFirst = true;
  for (const auto& i : cont) {
    if (!bFirst)
      std::cout << ", ";
    bFirst = false;
    print(i);
  }
  std::cout << " ]";
}
Run Code Online (Sandbox Code Playgroud)

所以那个重载从来没有被调用过。

一旦你这样做了,你的代码就不起作用了,因为你没有元素打印机。因此,用元素打印机替换您的其他循环打印机:

template<typename T>
void print(T const& i){
  std::cout << i;
}
Run Code Online (Sandbox Code Playgroud)

活生生的例子

测试代码:

std::vector<int> a={1,2,3};
print(a);
std::cout << "\n";
std::vector<std::vector<int>> b = {a, a, a};
print(b);
std::cout << "\n";
Run Code Online (Sandbox Code Playgroud)

输出:

[ 1, 2, 3 ]
[ [ 1, 2, 3 ], [ 1, 2, 3 ], [ 1, 2, 3 ] ]
Run Code Online (Sandbox Code Playgroud)

这是不够的,因为如果你想要一个更严肃的通用打印机,你真的应该做一些更有趣的事情来检测“这个对象是否可迭代”和“这个对象是否类似于元组”。检测Cont<A,B>模板是一个糟糕的替代品。

是检测某些内容是否可迭代的代码(忽略错误的检查答案,阅读我链接到的答案)。

然后为执行循环的print那个做一个 SFINAE 测试“参数是否可迭代” for(:)

您要做的下一件事是检测对象是否类似于元组。如果是,您想打印出元组的每个元素。这给你std::mapstd::unordered_map支持。请注意, astd::array既像元组又是可迭代的。

这比检测“可迭代”要困难一些,并且随着您使用的 C++ 标准变化更大,因为新版本的 C++ 正在扩展元组相似性。你可以偷懒,只检测std::pairand std::tuple,这将涵盖 99% 的用例。