我正在尝试为double
和vector<double>
编写一个重载函数。
我只是做了以下事情:
constexpr double degrees(double val) { return v * M_1_PI * 180.0; }
std::vector<double> degrees(const std::vector<double>& val)
{
std::vector<double> out;
out.reserve(val.size());
std::transform(val.begin(), val.end(), std::back_inserter(out), degrees);
return out;
}
我希望这是相当简单的,但它没有编译,我无法理解。编译器无法解决重载的degrees
函数,并不断抱怨
couldn't deduce template parameter '_UnaryOperation'
编辑:用reserve
修复零件,这是一个明显的错误。
您需要指定应将哪个重载传递给std::transform
。例如
std::vector<double> degrees(const std::vector<double>& val) {
std::vector<double> out;
out.reserve(val.size());
std::transform(val.begin(), val.end(), std::back_inserter(out), static_cast<double(*)(double)>(degrees));
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
return out;
}
BTW:std::vector<double> out(val.size());
将把out
构造为包含值为0.0
的val.size()
元素。我想这不是你想要的。默认初始化和reserve
都可以。
主要有两个问题
-
有两个函数重载,编译器无法从中自动选择,要使用哪一个。因此,您需要明确指定要传递给
std::transform
的一个。 -
std::vector<double> out(val.size());
将创建大小为val.size()
的双矢量,并且所有元素将用0.0
发起。CCD_ 15然后在这些元素之后添加元素。假设您不希望在out
向量中的val.size()
数量的0.0
先于实际元素。你需要一个std::vector::reserve
,用于不需要的真实位置。
也就是说,我建议使用lambda函数而不是自由函数,这样做的好处是可以将函数实现到调用它的位置:
std::vector<double> degrees(const std::vector<double>& val)
{
std::vector<double> out;
out.reserve(val.size()); // reserve some memory
std::transform(val.begin(), val.end(), std::back_inserter(out),
[](double ele) {return ele * M_1_PI * 180.0; }
);
return out;
}
查看演示
不能传递重载集,但可以传递带有重载调用运算符的函子:
struct degrees {
constexpr double operator()(double val) {return val * 0.3 * 180.0;}
std::vector<double> operator()(const std::vector<double>& val) {
std::vector<double> out(val.size());
std::transform(val.begin(), val.end(), std::back_inserter(out), degrees{});
return out;
}
};
我不想相信询问者不知道他们正在定义两个名称相同的函数degrees
,所以我会对我的答案另辟蹊径。
怎么可能,在这个呼叫
std::transform(val.begin(), val.end(), std::back_inserter(out), degrees);
degrees
未知?我的意思是,std::transform
应该尝试将degrees
应用于val
中的每个元素,因为这些元素中的每个都是double
,所以变换是否应该使用第一个重载,即需要double
的重载
尽管这种动机可能令人信服,但它需要编译器将degrees
应该被调用的决定延迟/推迟到它被实际调用的那一刻,即不是在std::transform
的调用位置,而是在std::transform
内部的(特别是在cppreference文档页上评估此可能实现中的表达式unary_op(*first1++)
时)。
这根本不可能,因为规则是编译器必须在函数的调用位置知道它的参数是什么。参考该示例,在std::transform
的调用位置,编译器不知道需要degree
的哪个重载。
一种方法是将degrees
封装在具有重载operator()
的函数对象中,如463035818_is_not_a_number所建议的;这样,对象degrees
在std::transform
调用站点上是已知的,并且只有std::transform
内部的,在对象的operator()
的调用站点上,编译器必须在operator()
的重载之间进行选择。