I've been trying more about multi threaded programming in c++, and i was having difficulty understanding std::promise
so i began searching for answers on this website, and low and behold, there is somebody with the same question as me. But reading the answer made me even more confused
this is the code in the answer that presumably is a similar implementation of std::packaged_task
template <typename> class my_task;
template <typename R, typename ...Args>
class my_task<R(Args...)>
{
std::function<R(Args...)> fn;
std::promise<R> pr; // the promise of the result
public:
template <typename ...Ts>
explicit my_task(Ts &&... ts) : fn(std::forward<Ts>(ts)...) { }
template <typename ...Ts>
void operator()(Ts &&... ts)
{
pr.set_value(fn(std::forward<Ts>(ts)...)); // fulfill the promise
}
std::future<R> get_future() { return pr.get_future(); }
// disable copy, default move
};
in this code,
1- what does this syntax mean template <typename R, typename ...Args> class my_task<R(Args...)>
, more specifically, what is the purpose of <R(Args...)>
?
2- why is there a foroward decleration for the class?
thanks
There was some brief discussion in the comments how 1 and 2 should be two separate questions, but I believe that they both are just two sides to the same exact question, for the following reasons:
template <typename> class my_task;
template <typename R, typename ...Args>
class my_task<R(Args...)>; ....
The first statement declares a template that takes a typename
as its sole template parameter. The second statement declares a specialization for that template class.
In this context:
R(Args...)
Will specialize for any typename
that matches a function. This template specialization will match any template instantiation that passes a function signature for a typename
. Barring any problems within the template itself, this template specialization will be used for:
my_task<int (const char *)>
or, a function that takes a const char *
parameter and returns an int
. The template specialization will also match:
my_task<Tptr *(Tptr **, int)>
or, a function that takes two parameters, Tptr **
and an int
, and returns a Tptr *
(here, Tptr
is some other class).
The template specialization will NOT match:
my_task<int>
Or
my_task<char *>
Because they are not function signatures. If you try to instantiate this template using a non-function typename
you're going to get a compilation error. Why?
Well, that's because the template is not defined:
template<typename> class my_task;
Don't think of this as just a forward declaration. it's a forward declaration of a template that takes a template parameter, and the template will not be defined anywhere. Rather, the template declaration allows for a subsequent template specialization declaration, that will match only specific types passed as a template parameter.
This is a common programming technique for restricting the kinds of typename
s or class
es that can be used with a particular template. Instead of allowing a template to be used with just any typename
or class
, the template can only be used with some subset. In this case, a function typename
, or signature.
It also makes it easier for the template itself to explicitly reference -- in this case -- to the template parameter's return type, and the parameter types. If the template has just a bland, single typename
as a template parameter, it can't easily access the function's return type, or the function parameter's types.