Search code examples
c++algorithmfunctionoverloadingstd

Unresolved overloaded function type in std::transfrom


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.


Solution

  • 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 (specifically, when evaluating the expression unary_op(*first1++) in this possible implementation on the cppreference doc page).

    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().