14

Sorry if this has been asked before, but I was unable to find it.

So im trying to educate myself about templates and the new C++11 features (mainly lambdas, something I always liked in other languages).

But in my tests I came to something I had no idea it worked, and I'm trying to understand how it works but cant figure it out..

The following code:

template <class Func>
void Test( Func callback ) {
    callback( 3 );
}

void Callback( int i ) {
    std::cout << i << std::endl;
}

int main( int argc, char** argv ) {
    Test( &Callback ); // this I was expecting to work, compiler will see its a pointer to a function
    Test( Callback ); // this also works, but how?!
    return 0;
}

If I understand how templates work, basically they're a scheme for the compiler to know what to build, so the first call Test( &Callback ); I was expecting to work because the compiler will see the template receives a function address and will assume the arguments should be a pointer.

But what is the second call? What is the template assuming it is? A copy of a functio (if that even makes any sense)?

Xeo
  • 129,499
  • 52
  • 291
  • 397
sap
  • 1,188
  • 1
  • 14
  • 25

4 Answers4

18

A function is implicitly convertible to a pointer to itself; this conversion happens pretty much everywhere. Test(Callback) is exactly the same as Test(&Callback). There is no difference. In both cases, Func is deduced to be void(*)(int).

Function pointers are weird. You can find out more about them in "Why do all these crazy function pointer definitions all work?"

Community
  • 1
  • 1
James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • thanks for the answer. so if i didnt use templates and declared Test like: void Test( void (*callback)(int) ){...} both calls would work as well. thats good to know. ill make sure i read the thread you linked. – sap Aug 18 '11 at 17:11
  • Why does `Test( &Callback );` work? Is a function pointer also implicitly convertible to its "value type"? – palapapa Dec 27 '22 at 16:21
3

Functions are implicitly convertible to function pointers. If fact there is no way to get a function value or reference. Though oddly you can create a function value type, you just can't assign anything to it.

Here is code snippit that demonstrates how lambdas and various callbacks react with templates.

deft_code
  • 57,255
  • 29
  • 141
  • 224
  • This is wrong. Function references are fine. If `Test` were declared as `void Test( Func &callback )`, then `Func` would be deduced to `void(int)`, and `Callback` would be passed by reference, without being converted to a pointer, to `Test`. – Johannes Schaub - litb Aug 29 '11 at 19:28
  • Wow! I guess it make sense that reference should be supported as well as pointers since they are so similar. Is it possible to declare a function value, and assign something to it? – deft_code Aug 30 '11 at 15:54
  • @deft I don't know what that means. What's a "function value"? – Johannes Schaub - litb Aug 30 '11 at 17:51
2

In C++, functions are not first-class objects, which means “function as value” makes no sense in it. That's why function name has always been implicitly convertible to pointer to it.

hamstergene
  • 24,039
  • 5
  • 57
  • 72
0

In C++ 11 (and boost and tr1) we have std::function as a template type for storing functors, lambdas and functions. So you can definitely have the concept of keeping a function value in a variable of type std::function. that variable can also be "empty" meaning that no function (reference) is stored in it. Then it cannot be called.

The original question relates to that in contrast to C, C++ allows function references. Plus, for compatibility reasons with C a function name can degenerate to a function pointer. But because of overloading things are more "interesting" in C++ than in C.

PeterSom
  • 2,067
  • 18
  • 16