Home > Blockchain >  Unresolved overloaded function type in std::transfrom
Unresolved overloaded function type in std::transfrom

Time:09-21

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

  1. 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.

  2. The std::vector<double> out(val.size()); will create a vector of double with size val.size() and all the elements will be initiated with 0.0. The std::back_inserter(out) then add element after these. Presumably, you do not want to have val.size() number of 0.0s in the out vector, prior to the actual elements. You need a std::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;
}

See a Demo

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

  • Related