How Can It Be Useful to Overload the "Function Call" Operator

How can it be useful to overload the function call operator?

This can be used to create "functors", objects that act like functions:

class Multiplier {
public:
Multiplier(int m): multiplier(m) {}
int operator()(int x) { return multiplier * x; }
private:
int multiplier;
};

Multiplier m(5);
cout << m(4) << endl;

The above prints 20. The Wikipedia article linked above gives more substantial examples.

Overload function call operator () in struct / what happens to arguments?

What happens when you do Check(0.1) in the call to std::unique is that a temporary object is created. This temporary object will have a lifetime to the end of the full expression.

The temporary object is passed like any other object to the std::unique function. This works because that argument is a templated argument and can have any type matching the usage of it.

In short the call to std::unique is roughly equivalent to something like this:

// Enter new nested local scope
{
Check temporary_object(0.1); // Create object
std::unique(..., temporary_object);
}
// Left nested scope, the `temporary_object` is destructed

Overloading function call operator () for indexing and assignments of a template object

The formula used for indexing into data is incorrect.

Update your function to return data[0] always but print the index. The output will make it clear that you are not using the right index.

T& operator() (int i, int j) {
int index = (i-1)*(this->cols) + j;
std::cout << "Index: " << index << std::endl;

return data[0]; // This is wrong but that's not the
// purpose of this suggested change.
}

Useful link: How to debug small programs

PS The correct index is i*(this->cols) + j.

Function call for overloaded operator (C++)

That's exactly what the answer you quote says, although it doesn't do so very well.

An operator overload can be a member, or a non-member.

For example, anOstream << aT can be resolved with a ostream& ostream::operator<<(T) (or similar) or with a free function ostream& operator<<(ostream&, T). Either of those can be called. That's just how it is. That's what the standard says.

Since we can't add things to ostream, the latter is how we go about it (though, for your own types, it would be pretty much up to you).

Notice how I chose a return type of ostream& for those examples; that's how "the return value goes back to cout": the left-hand operand is simply returned back by reference.

Why override operator()?

One of the primary goal when overloading operator() is to create a functor. A functor acts just like a function, but it has the advantages that it is stateful, meaning it can keep data reflecting its state between calls.

Here is a simple functor example :

struct Accumulator
{
int counter = 0;
int operator()(int i) { return counter += i; }
}
...
Accumulator acc;
cout << acc(10) << endl; //prints "10"
cout << acc(20) << endl; //prints "30"

Functors are heavily used with generic programming. Many STL algorithms are written in a very general way, so that you can plug-in your own function/functor into the algorithm. For example, the algorithm std::for_each allows you to apply an operation on each element of a range. It could be implemented something like that :

template <typename InputIterator, typename Functor>
void for_each(InputIterator first, InputIterator last, Functor f)
{
while (first != last) f(*first++);
}

You see that this algorithm is very generic since it is parametrized by a function. By using the operator(), this function lets you use either a functor or a function pointer. Here's an example showing both possibilities :

void print(int i) { std::cout << i << std::endl; }
...
std::vector<int> vec;
// Fill vec

// Using a functor
Accumulator acc;
std::for_each(vec.begin(), vec.end(), acc);
// acc.counter contains the sum of all elements of the vector

// Using a function pointer
std::for_each(vec.begin(), vec.end(), print); // prints all elements

Concerning your question about operator() overloading, well yes it is possible. You can perfectly write a functor that has several parentheses operator, as long as you respect the basic rules of method overloading (e.g. overloading only on the return type is not possible).

How to overload call operator() function with same type and parameters, but different return type?

Adapters:

struct Foo {
// these are your current operator() functions
int op1(int);
float op2(int);
};

struct FooAdapter1 {
Foo& foo;
auto operator()(int i) { return foo.op1(i); }
};

struct FooAdapter2 {
Foo& foo;
auto operator()(int i) { return foo.op2(i); }
};

So, instead of passing a Foo object like this:

std::invoke(foo,7); // no

You pass it via an adapter:

std::invoke(FooAdapter1{foo},7); // calls op1

And you give the Adapters good semantically sensible names, of course.


Alternatively, use an out argument to select the overload:

struct Foo {
// these are your current operator() functions
void operator()(int, int&);
void operator()(int, float&);
};

And then the somewhat ugly call:

float& result{};
std::invoke(foo,7,result); // selects the fist overload

Operator Functions Calling Mechanism

Yes, a use of an overloaded operator function is semantically a function call.

[over.match.oper]/2 in the C++ Standard says, emphasis mine:

If either operand [in an operator expression] has a type that is a class or an enumeration, a user-defined operator function might be declared that implements this operator or a user-defined conversion can be necessary to convert the operand to a type that is appropriate for a built-in operator. In this case, overload resolution is used to determine which operator function or built-in operator is to be invoked to implement the operator. Therefore, the operator notation is first transformed to the equivalent function-call notation as summarized in Table 12 ....

So the Standard rules about object lifetimes apply in exactly the same ways. There's also no reason a compiler's manipulation of behind-the-scenes things like a call stack would need to be different.

Your example is fine not because there's something special about operator functions, but because it doesn't return a reference to a local object. In return out;, out names the function parameter with reference type, so it refers to some other object from outside of the function scope. In this case, out refers to the variable print in main, and the lifetime of print goes to the end of main.

Overload function-call operator and return type

'should I return y1 by value or by reference?' By value undoubtedly, there's no good way to return a reference to a newly created object. If the cost of copying your objects is an issue then you should look to some kind of smart pointer technique to provide fast copying.

'And should I provide also a const version?' From what you have said you should only provide a const version.



Related Topics



Leave a reply



Submit