0

I am trying to call a function pointer using an explicit dereference. But the compiler throws an error:

no operator "*" matches these operands.

Here's a simplified version of my code:

#include <functional>
#include <iostream>

int add(int a, int b)
{
    return a + b;
}

std::function<int(int, int)> passFunction()
{
    return &add;
}

int main()
{
    int a{ 1 };
    int b{ 2 };

    std::cout << (*passFunction())(a, b);
    return 0;
}

The thing is, it works fine when I just write:

std::cout << passFunction()(a, b); // without asterix. 

which blows my mind.

I thought that, I messed up parentheses in function call. I tried different order and precedence, I called it with ampersand, and still compiler doesn't even flinch.

JeJo
  • 30,635
  • 6
  • 49
  • 88
kvrier
  • 23
  • 7
  • 4
    What gave you the idea that `passFunction` returns a pointer? What is the return type of that function? – Yksisarvinen Oct 28 '22 at 16:46
  • 1
    Functions are always pointers at the assembly level. `&add` and `add` are the same. But, you do not return a pointer anyway. You return a `std::function` which gets initialized from `&add`, i.e. `add`. – Michael Chourdakis Oct 28 '22 at 16:47
  • 1
    Probably the `&` in `return &add;` caused the misconception. – user4581301 Oct 28 '22 at 16:48
  • 1
    std::function is an object, not a function pointer. To call the embedded call, so yes just use `passFunction()(a,b);` or `auto fn = passFunction(); fn(a,b);` Read more here https://en.cppreference.com/w/cpp/utility/functional/function (cppreference is the goto place for C++/standard library documentation) – Pepijn Kramer Oct 28 '22 at 16:49
  • @Yksisarvinen My understanding of return &add; was that I'm getting back int pointer to an address of the add(int, int) function. I might sound confused- because I am. – kvrier Oct 28 '22 at 16:53
  • 1
    @kvrier That is true. But `std::function` isn't a pointer, it's an object and there's no pointer in the return type of your function. – Yksisarvinen Oct 28 '22 at 16:55
  • 1
    @kvrier The return type is `std::function` which as we can see from the [documentation](https://en.cppreference.com/w/cpp/utility/functional/function), does not have any overloaded `opeartor*`, so we can't use the dereference operator with that as also explained in my [answer](https://stackoverflow.com/a/74238524/12002570). – Jason Oct 28 '22 at 16:56
  • you can also use std::invoke, it work identical with function pointer or std::function – jls28 Oct 28 '22 at 17:08
  • 1
    Thank you for your answers! I've just started learning C++ and my ignorance tells my that function declaration type must match its return type, so how is it that `std::function` is somehow different from its return value `&add` and still compiles? – kvrier Oct 28 '22 at 17:15
  • 1
    The function returns a `std::function` object by value. It has been given the address of a function to return. Here we get to see the compiler being smart. It knows it needs `std::function` and hasn't been given one, but it knows that a `std::function` can be constructed from the address of a function, so it makes a temporary `std::function` out of the address and returns the temporary. – user4581301 Oct 28 '22 at 17:33
  • Note that [temporary](https://en.cppreference.com/w/cpp/language/lifetime#Temporary_object_lifetime) is an important term. A returned temporary variable needs to be used immediately or copied somewhere more permanent by the caller to be of much use because temporary variables don't live long, only until the end of the expression that spawned them. – user4581301 Oct 28 '22 at 17:34

3 Answers3

3

I'm trying to call a pointer function using a explicit dereference. But compiler throws an error: 'no operator "*" matches these operands'.

Type matters!

The return type of the passFunction is not a pointer, rather std::function. It is not something of dereferencable. Hence, you get the compiler error.


The thing is, it works fine when I just write: std::cout << passFunction()(a, b); without asterix [...]

The std::function meant for invoking/ calling. That is why passFunction()(a, b) works. It calls the operator() of std::function (i.e. equivalent to passFunction().operator()(a, b)).

That been said, if you simply return the function by auto (since C++14 - let the compiler deduce the type), you will get the actual function pointer, which you can call either by dereferencing (unnecessary) or directly.

using fun_t = int(*)(int, int); // function pointer type

auto passFunction()
//^^^ use auto --> type ==  int(*)(int, int)
// or use fun_t
{
    return &add;
}

now you can (unnecessary)

(*passFunction())(a, b);

or

passFunction()(a, b);

Now obvious question, "how the both syntax is possible ?". Read here in detail in the following posts:

JeJo
  • 30,635
  • 6
  • 49
  • 88
  • 2
    Excellent answer! And this is also the only one that explains how `int(*)(int, int)` works, which is the fundamental cause of the misunderstanding here – Mooing Duck Oct 28 '22 at 17:57
0

You shouldn't use the * operator on the std::function<int(int, int)> that passFunction() returns since it doesn't return a pointer that needs to be dereferenced.

This simple example will do:

#include <functional>
#include <iostream>

int add(int a, int b) {
    return a + b;
}

std::function<int(int, int)> passFunction() {
    return add; // or return &add - same thing when it comes to free functions
                // as opposed to member functions
}

int main() {
    int a{1};
    int b{2};

    std::cout << passFunction()(a, b);
}

I think the confusion comes from the fact that you do &add to return a function pointer - but look at what's important: The return type:

std::function<int(int, int)>

This is what passFunction() returns. It's not a pointer. It returns it by value. The function pointer you return is merely used as an argument to the std::function<int(int, int)>'s constructor.

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
0

but compiler throws an error: 'no operator "*" matches these operands'.

Your passFunction returns a std::function<int(int, int)> which as we can see from its documentation does not have any overloaded dereference operator. Thus we cannot write *passFunction(). The correct syntax would be as shown below:

//------------v----------------------->removed the * as std::function does not overload any such operator
std::cout << ( passFunction())(a, b)

Or

//----------v------------------------>no need for dereferencing
std::cout << passFunction()(a, b);
Jason
  • 36,170
  • 5
  • 26
  • 60