Я пытался больше о многопоточном программировании в 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- почему для класса существует прямая декларация?
Спасибо
В комментариях было краткое обсуждение того, как 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
как параметр шаблона, он не может легко получить доступ к типу возвращаемого значения функции или типам параметров функции.
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