Let's say I declare a thread with the following code:
#include <thread>
#include <iostream>
void printStuff(const char* c, long x) {
std::cout << x << " bottles of " << c << " on the wall\n";
}
int main()
{
std::thread t(printStuff, "beer", 900000000);
t.join();
}
How are the arguments printStuff, "beer," and 900000000 stored in the thread?
I know they are using a variadic template, where you first pass in a function and then a parameter pack of arguments. I am confused on how they forward all these template arguments, and then somehow call the inputted function with all the arguments when join or detach is called.
std::function has similar functionality where when you call std::bind it will store a function and its arguments inside the object, and then when you call the std::function object it will just execute the bound function with its arguments.
I am basically trying to implement my own version of std::function, for my own edification. I am curious how in C++ you would go about storing a function with a bunch of arbitrary parameters inside an object, and then having a method that would call the function with the passed in arguments.
I have looked at both the thread and std::function class, and both seem to be using tuples in some way to store their arguments. In a declaration of a tuple you have to specify what types you are storing in it:
std::tuple<int, std::string> tup;
How do std::function and thread get around this by storing their variadic arguments in tuples? Furthermore, how do they retrieve the function and call it with all of the arguments?
std::functionis a beast of a class so I won't pretend that this is anywhere close to as complete.std::functionuses type erasure and small object optimization but I'll use polymorphism and store a base class pointer to a semi-anonymous implementation of a function wrapper to show how it can be done. I say semi-anonymous because it actually has a name, but it's defined locally inside the function that instantiates it. Storing the pointer (or the empty state) will be done in astd::unique_ptr<funcbase>.The goal, as I've understood it, is to create a class with this basic interface:
That is, we need instances of
fn_with_args<R(Args...)>to be able to store function pointers / functors that when invoked with the stored arguments returnsR.Example usage:
Demo