Search code examples
c++c++11functor

Last argument of std::transform


According to cplusplus.com, std::transform applies an operation sequentially to the elements of one (1) or two (2) ranges and stores the result in the range that begins at result. The last argument of std::transform is generally a function, which does some operation on the elements of the first container, but suppose I have a functor object as follows :

struct functor {
  functor(int x) : x(x) {}
  int operator()(int x1) {return x + x1;}

  private :
    int x;
}

Then, in place of a function, I can also pass the instance of functor, like this :

vector<int> v1, v2;
v1.push_back(1);
v1.push_back(2);
v2.resize(v1.size());
std::transform(v1.begin(), v1.end(), v2.begin(), functor(1));

My question is, how does the compiler know whether a function or an instance of a functor class in passed to the std::transform function ? Also, if an instance is passed, what happens internally, regarding applying the function to the elements of the first container ?


Solution

  • std::transform is a template (well, two overloads for one or two input ranges) function which possible implementation for one range:

    template<class InputIt, class OutputIt, class UnaryOperation>
    OutputIt transform(InputIt first1, InputIt last1, OutputIt d_first, 
                       UnaryOperation unary_op)
    {
        while (first1 != last1) {
            *d_first++ = unary_op(*first1++);
        }
        return d_first;
    }
    

    and for two ranges

    template<class InputIt1, class InputIt2, 
             class OutputIt, class BinaryOperation>
    OutputIt transform(InputIt1 first1, InputIt1 last1, InputIt2 first2, 
                       OutputIt d_first, BinaryOperation binary_op)
    {
        while (first1 != last1) {
            *d_first++ = binary_op(*first1++, *first2++);
        }
        return d_first;
    }
    

    The requirements on the last argument is that it has an operator () applicable to types that you get by dereferencing provided iterators (i.e. its arguments and return type are implicitly convertible to them). So it could be plain function, lambda, or any user type with such operator.