0

From this question I got a good understanding of functors (function objects); how to initialize and call them. I wrote some code to play around with this for my own understanding

class Foo
{
private:
   int x;
public:
   Foo(int x) : x(x) {}
   int operator()(int y) { return x + y; }
};

Foo poo(50);

int a = poo(50);

std::cout << a;

std::vector<int> vec(10);
std::vector<int> pec(10);

std::transform(vec.begin(), vec.end(), vec.begin(), poo(1));

and receive the following compilation error

Severity    Code    Description Project File    Line    Suppression State
Error   C2064   term does not evaluate to a function taking 1 arguments 

I looked within the above question at some of the comments and tried a lambda expression instead

std::transform(vec.begin(), vec.end(), vec.begin(), [](Foo poo) {return poo(1); });

which works but I don't understand why the accepted answer using std::transform(in.begin(), in.end(), out.begin(), add_x(1)); fails. Why do I have to use a lambda expression? Another answer is doing the same thing but it still will result in a compilation error. Why is that?

Mushy
  • 2,535
  • 10
  • 33
  • 54
  • 9
    It sounds like a typo. `poo(1)` -> `Foo(1)`. – R Sahu Oct 11 '17 at 20:23
  • I think it's more of a case of the somewhat misleading error message making you miss the fact that you're referencing something that doesn't exist: `poo`. – Etienne de Martel Oct 11 '17 at 20:39
  • 1
    `poo(1)` is an `int`; as the error message says, it it not a function taking 1 argument. `Foo(1)` is a function object with an `operator()` that takes a single argument of type `int`. – Pete Becker Oct 11 '17 at 21:00
  • I misunderstood the results from the question. I thought I could pass the function object into the transform rather than the class object. – Mushy Oct 11 '17 at 21:43
  • What is the reason for overloading () anyway? – Dumbo Oct 11 '17 at 22:46
  • @SaeidYazdani I'm practicing function objects in c++11 and may be doing something I don't need to because I'm a noob trying to learn this complex language but I have good references to learn from. – Mushy Oct 11 '17 at 23:04

2 Answers2

3

This code works just fine.

#include <iostream>
#include <array>

class add_x
{
private:
   int x;

public:
   add_x(int x) : x(x) {}

   int operator()(int y) /* consider adding const here */
   { return x + y; }
};


int main()
{
    std::array<int, 5> input { 1, 4, 9, 16, 25 };
    std::array<int, 5> output;
    std::transform(begin(input), end(input), begin(output), add_x(1));
    for ( auto& val : output ) std::cout << val << "\n";
}

However, it's probably a good idea to make the invocation a const member function since it doesn't mutate the functor. That may also make it work with more versions of the Standard library.

The difference between this and your lambda version is that here, the constant 1 is passed to the constructor to create one functor object, and the data are passed sequentially to the operator of that single functor instance. In your lambda, a new object is created from each datum by calling the conversion constructor, and then the constant is passed to the operator. That is, x and y are swapped by your workaround, and also the number of instances changed.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
1

It also works if you add a definition:

Foo poo(1);

and just send poo into transform, without the (1) invocation. Transform requires an object with a () operator to call, and declaring it separately makes it a little more clear what its scope is.

Steve
  • 169
  • 6