What does this syntax mean, `class template <class R, class ...Args> class name<R(Args...)>`
Asked Answered
L

2

6

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

Leeuwarden answered 2/12, 2015 at 1:52 Comment(6)
Woah woah, one question per question pleaseCordalia
should i split it to 3 different questions? they all seem closely related, especially 1 and 2Leeuwarden
Yes, I think so. You have the beginnings of three pretty good questions here, but they shouldn't be lumped together into one and they could also do with a little fleshing out and research. Being related isn't the same as, well, as being the same.Cordalia
i would research them, but i dont know what to research for, i can't exactly type class template <class R, class …Args> class name<R(Args…)> in google, it wouldn know what am talking aboutLeeuwarden
This might help #4642579Zulemazullo
thanks Pradhan, this really helpedLeeuwarden
Q
5

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 typenames or classes 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.

Quarterhour answered 2/12, 2015 at 2:22 Comment(1)
Thank you so much, now it all makes sense. I knew it was a specialization syntax, but i have never seen one like that before.Leeuwarden
D
2

1: What does this syntax mean template <typename R, typename ...Args> class my_task<R(Args...)>

This is a specialization of the class template my_task. The <R(Args...)> after the name means it is specialized for that type, and that type is a function. R(Args...) is the type of a function taking Args parameters and returning R. So, my_task<void()> mt; for example would make Args be an empty parameter pack, and R would be void.

2: Why is there a forward declaration for the class?

The class is declared, but unlike an ordinary forward declaration, the un-specialized version isn't defined. This class is only intended to work when the type is a function, so if someone tries to use something that isn't a function (like my_task<int>), it will give an error about the type being undefined.

my_task<void*(int, int)> mt1; //R = void*, Args = int, int
my_task<int> mt2; //error: use of undefined class
Drupe answered 2/12, 2015 at 2:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.