Что означает этот синтаксис: `шаблон класса & lt; класс R, класс … Args & gt; имя класса & lt; R (Args …) & gt; `

Я пытался больше о многопоточном программировании в C ++, и у меня были трудности с пониманием std::promise поэтому я начал искать ответы на этом сайте, и вот, есть кто-то с тем же вопросом, что и я. Но чтение ответа еще больше запутало меня
это код в ответе, который, вероятно, является аналогичной реализацией 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
};

в этом коде,

1- что означает этот синтаксис template <typename R, typename ...Args> class my_task<R(Args...)>более конкретно, какова цель <R(Args...)> ?

2- почему для класса существует прямая декларация?

Спасибо

2

Решение

В комментариях было краткое обсуждение того, как 1 и 2 должны быть двумя отдельными вопросами, но я считаю, что они оба являются просто двумя сторонами одного и того же точного вопроса по следующим причинам:

template <typename> class my_task;

template <typename R, typename ...Args>
class my_task<R(Args...)>; ....

Первый оператор объявляет шаблон, который принимает typename в качестве единственного параметра шаблона. Второе утверждение объявляет специализацию для этого шаблонного класса.

В данном контексте:

 R(Args...)

Будет специализироваться на любом typename это соответствует функции. Эта специализация шаблона будет соответствовать любому экземпляру шаблона, который передает сигнатуру функции для typename, За исключением любых проблем внутри самого шаблона, эта специализация шаблона будет использоваться для:

 my_task<int (const char *)>

или функция, которая принимает const char * параметр и возвращает int, Специализация шаблона также будет соответствовать:

 my_task<Tptr *(Tptr **, int)>

или функция, которая принимает два параметра, Tptr ** и intи возвращает Tptr * (Вот, Tptr это какой-то другой класс).

Специализация шаблона НЕ будет соответствовать:

 my_task<int>

Или же

 my_task<char *>

Потому что они не являются сигнатурами функций. Если вы попытаетесь создать экземпляр этого шаблона, используя не-функцию typename вы получите ошибку компиляции. Зачем?

Ну, это потому, что шаблон не определен:

template<typename> class my_task;

Не думайте об этом как о предварительной декларации. это предварительное объявление шаблона, которое принимает параметр шаблона, и шаблон нигде не будет определен. Скорее, объявление шаблона допускает последующее объявление специализации шаблона, которое будет соответствовать только определенным типам, передаваемым в качестве параметра шаблона.

Это распространенный метод программирования для ограничения видов typenameс или classЭто может быть использовано с конкретным шаблоном. Вместо того, чтобы позволить шаблону использоваться только с любым typename или же classшаблон может использоваться только с некоторым подмножеством. В этом случае функция typenameили подпись.

Это также облегчает для самого шаблона явную ссылку — в данном случае — на тип возвращаемого параметра шаблона и типы параметров. Если шаблон имеет только мягкий, одиночный typename как параметр шаблона, он не может легко получить доступ к типу возвращаемого значения функции или типам параметров функции.

3

Другие решения

1: Что означает этот синтаксис template <typename R, typename ...Args> class my_task<R(Args...)>

Это специализация шаблона класса my_task, <R(Args...)> после имени означает, что оно специализировано для этого типа, и этот тип является функцией. R(Args...) это тип функции, принимающей Args параметры и возврат R, Так, my_task<void()> mt; например сделал бы Args быть пустым пакетом параметров, и R было бы void,

2: почему есть предварительное объявление для класса?

Класс объявлен, но в отличие от обычного предварительного объявления, не специализированная версия не определена. Этот класс предназначен для работы только тогда, когда тип является функцией, поэтому, если кто-то пытается использовать что-то, что не является функцией (например, my_task<int>), он выдаст ошибку о том, что тип не определен.

my_task<void*(int, int)> mt1; //R = void*, Args = int, int
my_task<int> mt2; //error: use of undefined class
2

По вопросам рекламы [email protected]