我想编写一个模板函数,将某些函数应用于来自两个 vector 的元素对。结果应该是一个新的结果 vector 。我希望这是一个模板化函数,以便它适用于不同类型。
我之前试过这个定义。但是,当我尝试将它应用于某些特定函数时,出现编译错误。
#include <vector>
#include <cmath>
#include <iostream>
#include <functional>
using namespace std;
template<typename T1, typename T2, typename T3>
vector<T3> mapzip2(const vector<T1> &xs, const vector<T2> &ys, std::function<T3(T1, T2)> l) {
if (xs.size() != ys.size())
throw runtime_error("mapzip2: container sizes (" + to_string(xs.size()) +
" and " + to_string(ys.size()) + ") do not match");
vector<T3> result;
result.reserve(xs.size());
for (int i = 0; i < xs.size(); i++)
result.push_back(l(xs[i], ys[i]));
return result;
}
constexpr double PRECISION = 1E-6;
bool feq(double a, double b) {
return abs(a - b) < PRECISION;
}
int main() {
vector<double> a = {0.3, 0.42, 0.0, -7.34};
vector<double> b = {0.3, 0.42, 0.0, -7.34};
// compilation error: no matching function for call to
// ‘mapzip2(std::vector<double>&, std::vector<double>&, bool (&)(double, double))’
vector<bool> result = mapzip2(a, b, feq);
for (bool b: result) cout << b << ' ';
cout << endl;
}
类型推导有什么问题?
最佳答案
你遇到了一个先有鸡还是先有蛋的问题。
T3
输入
template<typename T1, typename T2, typename T3>
T3 mapzip2(const vector<T1> &xs, const vector<T2> &ys, std::function<T3(T1, T2)> l)
必须从第三个参数推导出来,a std::function<T3(T1, T2)>
但是当你打电话的时候
bool feq(double a, double b) {
return abs(a - b) < PRECISION;
}
// ...
vector<bool> result = mapzip2(a, b, feq);
你调用mapzip()
与 feq
可以转换为 std::function<bool(double, double)>
但不是 std::function<bool(double, double)>
所以 T3
类型不能推断为 bool
因为要转换 feq
至 std::function<bool(double, double)>
你必须知道,在推导之前,T3
是bool
.
可能的解决方案:
(1) 显式模板类型调用mapzip()
vector<bool> result = mapzip2<double, double, bool>(a, b, feq);
这样编译器就知道T3
是bool
, 所以转换 feq
至 std::function<bool(double, double)>
(2) 构造一个std::function<bool(double, double)>
与 feq
vector<bool> result = mapzip2(a, b, std::function<double, double, bool>{feq});
所以编译器可以接收到一个std::function
作为第三个参数并推导出T3
从它。
(3)(更灵活,恕我直言,三者中最好的)避免 std::function
并为函数使用更通用的函数类型名
template<typename T1, typename T2, typename F>
auto mapzip2(const vector<T1> &xs, const vector<T2> &ys, F l) {
if (xs.size() != ys.size())
throw runtime_error("mapzip2: container sizes (" + to_string(xs.size()) +
" and " + to_string(ys.size()) + ") do not match");
vector<decltype(l(xs[0], ys[0]))> result; // <-- use decltype() !
result.reserve(xs.size());
for (int i = 0; i < xs.size(); i++)
result.push_back(l(xs[i], ys[i]));
return result;
}
观察 decltype()
的使用推断返回 vector 的类型(旧的 T3
)和 auto
的使用(从 C++14 开始)用于函数的返回类型。
如果你不能使用C++14(只能使用C++11),你必须添加尾随返回类型
template<typename T1, typename T2, typename F>
auto mapzip2(const vector<T1> &xs, const vector<T2> &ys, F l)
-> std::vector<decltype(l(xs[0], ys[0]))>
{
}
还请注意——正如 ypnos 在评论中指出的那样——你的原始签名 mapzip2()
错了:你返回 result
, 一个 std::vector<T3>
, 不是 T3
.
关于c++ - 带有模板参数的 std::function,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57375532/