简体   繁体   中英

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.

You need to specify which overload should be passed to std::transform . Eg

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.

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.0 s 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

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;
    }
};

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM