I am trying to write an overload function for both double
and vector<double>
.
I just did the following:
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;
}
I expect this to be rather straightforward, but it does not compile, and I cannot figure it out. The compiler cannot resolve the overloaded degrees
function, and keeps complaining
couldn't deduce template parameter '_UnaryOperation'
Edit: fix the part with reserve
, it is an obvious mistake.
CodePudding user response:
You need to specify which overload should be passed to std::transform
. E.g.
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());
would construct out
as containing val.size()
elements with value 0.0
. I suppose this is not what you want. Default-initialization and reserve
would be fine.
CodePudding user response:
There are mainly two issues
There are two functions overloads from which compiler can not choose it automatically, which one to use. So you need to explicitly specify which one is to pass to the
std::transform
.The
std::vector<double> out(val.size());
will create a vector of double with sizeval.size()
and all the elements will be initiated with0.0
. Thestd::back_inserter(out)
then add element after these. Presumably, you do not want to haveval.size()
number of0.0
s in theout
vector, prior to the actual elements. You need astd::vector::reserve
there, for unwanted real locations.
That being said, I would suggest having a lambda function instead of a free function, which has the advantage of having the implementation of the function right into the place where it is called:
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;
}
CodePudding user response:
You cannot pass an overload set around, but you can pass a functor with overloaded call operator:
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;
}
};
CodePudding user response:
I don't want to believe that the asker didn't know they are defining two functions with the same name degrees
, so I'll give another shade to my answer.
How is it possible, in this call
std::transform(val.begin(), val.end(), std::back_inserter(out), degrees);
that degrees
is not known? I mean, std::transform
should try to apply degrees
to each element in val
, and since each of those elements is a double
, isn't it obvious that transform should make use of the first overload, the one which takes a double
?
As convincing as this motivation might be, though, it would require the compiler to delay/defer the decision of what degrees
should be called to the moment it's actually called, i.e. not at the call site of std::transform
, but inside std::transform
.
This is simply not possible, as the rules are that the compiler must know at the call site of a function what its arguments are. With reference to the example, at the call site of std::transform
the compiler has no idea which of the overloads of degree
is needed.
One way around is to wrap degrees
in a function object with overloaded operator()
, as suggested by 463035818_is_not_a_number; doing so, the object degrees
would be known at std::transform
call site, and only inside std::transform
, at the call site of the object's operator()
would the compiler have to choose between the overloads of operator()
.