Search code examples
c++function-pointersstd-function

What exactly is represented by the template parameter passed to std::function template?


std::function itself offers a great utility- it provides type erasure in order to generically store / provide access to callables. Its flexibility is great:

#include <functional>
#include <iostream>

void printer() {
    std::cout << "I print!";
}

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

int main() {
    std::function<void()> fun1 = printer;       // fun1() calls printer()
    std::function<int(int, int)> fun2 = adder;  // fun2(1, 2) calls adder(1, 2)

    std::function<void()> fun3 = [](){};        // fun3() will do nothing - same for the lambda
    std::function<int(int, int)> fun4 =
            [](int a, int b) { return a + b; }; // fun4(1, 2) will yield the sum
}

And, to be honest, everything makes sense. std::function<void()> says that it's a function, which, when called, returns void and takes no (()) arguments. Ditto for std::function<int(int, int)> - when called, it returns an int and requires two ints as its arguments.

While intuitive, I believe I lack fundamental understanding of that exactly is the explicit template parameter. What exactly is void() or int(int, int)? They cannot be function pointers, becasue when I do:

int main() {
    using type = void();

    type x = printer;
}

I get the following warning and an error:

main.cpp:15:10: warning: declaration of 'void x()' has 'extern' and is initialized
 type x = printer;
      ^
main.cpp:15:14: error: function 'void x()' is initialized like a variable
 type x = printer;
          ^~~~~~~

Well, obviously it looks like a variable - I wanted it to be a variable. However, if I wanted a function pointer, I would've had to do:

using type = void(*)();

instead of:

using type = void();

What exactly is the type with omitted *? What exactly is represented by the intuitive explicit template parameters when used with, for example, the std::function?


Solution

  • What exactly is the type with omitted *?

    Think about it. A type "followed by" a * means "pointer to that type". If you don't "follow" a type with a *, then the type means just that type. So if you have a function pointer, then it is a pointer to... a function type.

    Therefore, types like void() are function types.

    Function types are distinct from object types, but they are still types. So you can play most of the type-based games with them that C++ allows. But since they're not object types, you cannot create objects of function type.