Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

function pointers and return type conversions

Suppose I have a function that performs some side effect and then returns an answer:

int foo()
{
    perform_some_side_effect();
    return 42;
}

I want to bind foo to a function pointer, but I'm not interested in the answer, just the side effect:

void (*bar)() = foo;

However, this appears to be a type error:

error: invalid conversion from ‘int (*)()’ to ‘void (*)()’

What is the rationale behind that error? Why doesn't the type system allow me to ignore the answer?


On a side note, it works if I wrap the function pointer in a std::function:

std::function<void()> baz = foo;

How does std::function (apparently) manage to circumvent this restriction in the type system?

like image 624
fredoverflow Avatar asked Jun 02 '12 23:06

fredoverflow


2 Answers

What is the rationale behind that error? Why doesn't the type system allow me to ignore the answer?

The reason is that the types are different, and the generated code at the place of call (through the function pointer) is different. Consider a calling convention where all arguments are written to the stack and space for the return value is also reserved in the stack. If the call goes through a void (*)() then no space will be reserved in the stack for the return value, but the function (unaware of how it is being called) will still write the 42 to the location where the caller should have reserved space.

How does std::function (apparently) manage to circumvent this restriction in the type system?

It does not. It creates a function object that wraps the call to the actual function. It will contain a member like:

void operator()() const {
   foo();
}

Now when the compiler processes the call to foo it knows what it has to do to call a function that returns an int and it will do so according to the calling convention. Because the template does not return, it will just ignore the value --that was actually returned.

like image 122
David Rodríguez - dribeas Avatar answered Oct 18 '22 18:10

David Rodríguez - dribeas


std::function need only be source compatible- that is, it can generate a new class which generates new caling code that ignores the result. The function pointer must be binary compatible and cannot do that job- void(*)() and int(*)() point to the exact same code.

like image 35
Puppy Avatar answered Oct 18 '22 17:10

Puppy