C++ 模板:如何使用 2 个类型名,而只有 1 个是函数的输入?

C++ template: how to use 2 typenames while only 1 is function's input?

对于如下所示的一段简单代码:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <unordered_map>
#include <vector>
using namespace std;

static void print(const vector<int>& v) {
    copy(
        begin(v),
        end(v),
        ostream_iterator<int>{cout, ", "}
    );
    cout << endl;
}

int main() {
    vector<pair<int, string>> v {1, 2, 3, 4, 5};

    cout << endl << "In vector:" << endl;
    print(v);

    return 0;
}

我尝试将模板编程用于打印目的,因为我想将 container 概括为任何类型(vectormaplist 等) ,并且元素也可以是任何类型(intdouble 等)。

template <typename C, typename T>
static void print(const C& container) {
    copy(
        begin(container),
        end(container),
        ostream_iterator<T>{cout, ", "}
    );
    cout << endl;
}

但是,它不会编译:

In function 'int main()':
prog.cc:31:12: error: no matching function for call to 'print(std::vector<int>&)'
   31 |     print(v);
      |            ^
prog.cc:18:13: note: candidate: 'template<class C, class T> void print(const C&)'
   18 | static void print(const C& container) {
      |             ^~~~~
prog.cc:18:13: note:   template argument deduction/substitution failed:
prog.cc:31:12: note:   couldn't deduce template parameter 'T'
   31 |     print(v);
      |            ^

我的猜测是 typename T 不是通过函数 print() 显式输入的,而是由 ostream_iterator<int>{cout, ", "} 调用的,编译器不知道如何推断其类型(为什么?)。

我想知道如何将两个类型名称(CT)传递给 print() 函数,尽管只有类型名称 C 是输入?

您不需要指定第二个模板参数。为此,大多数 STL 容器都有一个成员 value_type。所以你的功能需要是:

template <typename C, typename T = typename C::value_type>
static void print(const C& container) {
    copy(
        begin(container),
        end(container),
        ostream_iterator<T>{cout, ", "}
    );
    cout << endl;
}

您需要在调用 print 时明确指定类型 T(例如 print(v, int),或者您编写 print 以便它派生容器本身。执行此操作的正常方法是使用 typename C::value_type,它存在于所有标准容器中:

template <typename C>
void print(const C& container) {
    using T = typename C::value_type;
    copy(
        begin(container),
        end(container),
        ostream_iterator<T>{cout, ", "}
    );
    cout << endl;
}

如果你不喜欢这种方式,或者你的容器可能并不总是有一个value_type成员,那么你可以很容易地直接导出值类型:

template <typename C>
void print(const C& container) {
    using T = std::remove_const_t<decltype(*std::cbegin(container))>;
    copy(
        std::cbegin(container),
        std::cend(container),
        ostream_iterator<T>{cout, ", "}
    );
    cout << endl;
}