std::transfrom中未解析的重载函数类型



我正在尝试为doublevector<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.0val.size()元素。我想这不是你想要的。默认初始化和reserve都可以。

主要有两个问题

  1. 有两个函数重载,编译器无法从中自动选择,要使用哪一个。因此,您需要明确指定要传递给std::transform的一个。

  2. 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所建议的;这样,对象degreesstd::transform调用站点上是已知的,并且只有std::transform内部的,在对象的operator()的调用站点上,编译器必须在operator()的重载之间进行选择。

相关内容

  • 没有找到相关文章

最新更新