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
概括为任何类型(vector
、map
、list
等) ,并且元素也可以是任何类型(int
、double
等)。
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, ", "}
调用的,编译器不知道如何推断其类型(为什么?)。
我想知道如何将两个类型名称(C
和 T
)传递给 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;
}
对于如下所示的一段简单代码:
#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
概括为任何类型(vector
、map
、list
等) ,并且元素也可以是任何类型(int
、double
等)。
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, ", "}
调用的,编译器不知道如何推断其类型(为什么?)。
我想知道如何将两个类型名称(C
和 T
)传递给 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;
}