TABATA
TABATA

Reputation: 69

g++ generates errors for an argument of transform()

g++ generates errors for this code. I have to change std::sin to (double (*)(double))std::sin. Why?

#include <iostream>
#include <list>
#include <algorithm>
#include <cmath>

int main(int argc, char *argv[])
{
    std::list<double> radians = {0.0, 3.14/2, 3.14};
    std::list<double> sines(radians.size());
    std::transform(radians.begin(), radians.end(), sines.begin(), std::sin);

    for(auto i = radians.begin(), j = sines.begin(); i != radians.end(); i++, j++)
        std::cout << "Angle and sine: " << *i << " " << *j << std::endl;

    return 0;
}

Upvotes: 1

Views: 78

Answers (3)

songyuanyao
songyuanyao

Reputation: 172924

Because std::transform is function template, the type of function object parameter is declared as template parameter which needs to be deduced from the function argument. But std::sin has several overloads, there's no context to determine which overload should be selected and then to be used to deduce the template argument.

You can use static_cast (or c-style cast as you showed) to specify one.

static_cast may also be used to disambiguate function overloads by performing a function-to-pointer conversion to specific type, as in

std::for_each(files.begin(), files.end(),
              static_cast<std::ostream&(*)(std::ostream&)>(std::flush));

e.g.

std::transform(radians.begin(), radians.end(), sines.begin(), static_cast<double(*)(double)>(std::sin));

Or specify the template argument explicitly to bypass the template argument deduction. With the known function parameter type overload resolution would be performed to select the proper overload.

std::transform<std::list<double>::iterator, 
               std::list<double>::iterator, 
               double(*)(double)
              >(radians.begin(), 
                radians.end(), 
                sines.begin(), 
                std::sin
               );

Upvotes: 6

Timur Kukharskiy
Timur Kukharskiy

Reputation: 303

So writed. You can use ...

 using namespace std;

 double sinn(double i){
     return sin(i);
 }

this function instead of sin.

Upvotes: -1

Bob__
Bob__

Reputation: 12759

Given your use case, another way to disambiguate the function overloads is to write a lambda accempting a specific type:

std::list<double> radians = {0.0, 3.14/2, 3.14};
std::list<double> sines;
std::transform(radians.begin(), radians.end(),
               std::back_inserter(sines),
               [] (double x) { return std::sin(x); });
//                 ^^^^^^ 

Edit

As noted by walnut, since C++14, we can use auto and let the compiler deduce the value type from the iterators.

std::transform(radians.begin(), radians.end(),
               std::back_inserter(sines),
               [] (auto x) { return std::sin(x); });

Upvotes: 2

Related Questions