Почему в следующем примере `std :: transform` нужен функциональный указатель вместо функционального объекта? - PullRequest
2 голосов
/ 17 июня 2019

Шаблон функции std::transform() берет диапазон, оперирует с ним по компонентам с оператором и сохраняет результат в другом диапазоне.В следующем примере функция принимает обобщенный std::initializer_list с именем nl и работает с ним с (std::string (*)(T)) std::to_string, чтобы преобразовать все свои записи в строки, а затем сохраняет результат в массиве строк с именем buffer. * 1006.*

class num_list
{
public:
    template<typename T>
    num_list(std::initializer_list<T> nl):
        size{nl.size()},
        buffer(new std::string[size])
    {
        std::transform(nl.begin(), nl.end(), // input sequence
        buffer,                              // output result
        (std::string (*)(T))std::to_string); // unary operator
    }
    //...
private:
    std::size_t size;
    std::string * buffer;
};

Мне интересно, зачем нам нужно вводить std::to_string в указатель на функцию, чтобы это работало.Почему код не компилируется с C ++ 11, если мы отбрасываем приведение к типу указатель на функцию (std::string (*)(T))?Я не могу расшифровать жалобу, выданную компилятором.

error: no instance of overloaded function "std::transform" matches the argument list

1 Ответ

5 голосов
/ 17 июня 2019

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

Когда вы приведете std::to_string кa std::string (*)(T), теперь у вас есть только один тип для вывода компилятором, который он делает, и вы можете успешно скомпилировать.

Вместо приведения вы можете использовать универсальную лямбду для пересылки на std::to_stringкак

std::transform(nl.begin(), nl.end(), // input sequence
buffer,                              // output result
([](auto&& val){ return std::to_string(val);});

, но для этого требуется как минимум C ++ 14.Для C ++ 11 вы можете использовать T для типа параметра как

std::transform(nl.begin(), nl.end(), // input sequence
buffer,                              // output result
([](const T& val){ return std::to_string(val);});
...