g ++ генерирует ошибки для аргумента transform () - PullRequest
1 голос
/ 12 февраля 2020

g ++ генерирует ошибки для этого кода. Я должен изменить std::sin на (double (*)(double))std::sin. Почему?

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

Ответы [ 3 ]

6 голосов
/ 12 февраля 2020

Поскольку std::transform является шаблоном функции, тип параметра объекта функции объявляется как параметр шаблона, который должен быть выведен из аргумента функции. Но std::sin имеет несколько перегрузок, нет контекста, чтобы определить, какую перегрузку следует выбрать и затем использовать для вывода аргумента шаблона.

Вы можете использовать static_cast (или c стиль приведения, как вы показали), чтобы указать его.

static_cast также может использоваться для устранения неоднозначности перегрузок функций путем выполнения преобразования функции в указатель для указания c введите, как в

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

например,

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

Или укажите явно аргумент шаблона, чтобы обойти вывод аргумента шаблона. При известном типе параметра функции разрешение перегрузки будет выполнено для выбора правильной перегрузки.

std::transform<std::list<double>::iterator, 
               std::list<double>::iterator, 
               double(*)(double)
              >(radians.begin(), 
                radians.end(), 
                sines.begin(), 
                std::sin
               );
2 голосов
/ 12 февраля 2020

Учитывая ваш вариант использования, еще один способ устранить неоднозначность перегрузок функций - написать лямбду, принимающую указанный тип c:

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); });
//                 ^^^^^^ 

Редактировать

Как отмечает walnut , начиная с C ++ 14, мы можем использовать auto и позволить компилятору выводить тип значения из итераторов.

std::transform(radians.begin(), radians.end(),
               std::back_inserter(sines),
               [] (auto x) { return std::sin(x); });
0 голосов
/ 12 февраля 2020

Так написано. Вы можете использовать ...

 using namespace std;

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

эту функцию вместо греха.

...