int main() {
int i=1234, j=5678, k=9;
std::function f=[&i, j, &k] {return i+j+k;};
i =
1;
j = 2;
k = 3;
std::cout << f() << std::endl;
}
Последний способ заодно гарантирует, что захвачены только необходимые переменные, потому что ссылка на локальную переменную, отсутствующую в списке захвата, приведёт к ошибке компиляции. Выбирая этот вариант, нужно соблюдать осторожность при доступе к членам класса, если лямбда-функция погружена в функцию-член класса. Члены класса нельзя захватывать непосредственно; если к ним необходим доступ из лямбда-функции, то необходимо захватить указатель this
, включив его в список захвата. В следующем примере лямбда-функция захватывает this
для доступа к члену класса some_data
:
struct X {
int some_data;
void foo(std::vector& vec) {
std::for_each(vec.begin(), vec.end(),
[this](int& i){ i += some_data; });
}
};
В контексте параллелизма лямбда-функции особенно полезны для задания предикатов функции std::condition_variable::wait()
(см. раздел 4.1.1) и в сочетании с std::packaged_task<>
(раздел 4.2.1) или пулами потоков для упаковки небольших задач. Их можно также передавать конструктору std::thread
в качестве функций потока (раздел 2.1.1) и в качестве исполняемой функции в таких параллельных алгоритмах, как parallel_for_each()
(раздел 8.5.1).
А.6. Шаблоны с переменным числом параметров
Функции с переменным числом параметров, например printf
, используются уже давно, а теперь появились и шаблоны с переменным числом параметров (variadic templates). Такие шаблоны применяются во многих местах библиотеки С++ Thread Library. Например, конструктор std::thread
для запуска потока (раздел 2.1.1) — это шаблон функции с переменным числом параметров, a std::packaged_task<>
(раздел 4.2.2) — шаблон класса с переменным числом параметров. С точки зрения пользователя, достаточно знать, что шаблон принимает неограниченное количество параметров, но если вы хотите написать такой шаблон или просто любопытствуете, как это работает, то детали будут небезынтересны.
При объявлении шаблонов с переменным числом параметров, по аналогии с обычными функциями, употребляется многоточие ( ...
) в списке параметров шаблона:
template
class my_template {};
Переменное число параметров допустимо и в частичных специализациях шаблона, даже если основной шаблон содержит фиксированное число параметров. Например, основной шаблон std::packaged_task<>
(раздел 4.2.1) — это простой шаблон с единственным параметром:
template
class packaged_task;
Однако этот основной шаблон нигде не конкретизируется, а служит лишь основой для частичных специализаций:
template
class packaged_task;
Именно внутри частичной специализации и содержится реальное определение класса; в главе 4 мы видели, что для объявления задачи, которая принимает параметры типа std::string
и double
и возвращает результат в виде объекта std::future
, можно написать std::packaged_task
.
На примере этого объявления демонстрируются два дополнительных свойства шаблонов с переменным числом параметров. Первое сравнительно простое: разрешается в одном объявлении задавать как обычные параметры шаблона (скажем ReturnType
), так и переменные ( Args
). Второе свойство — это использование Args...
в списке аргументов специализации шаблона для обозначения того, что здесь должны быть перечислены фактические типы, подставляемые вместо Args
в точке конкретизации шаблона. На самом деле, поскольку это частичная специализация, то работает она, как сопоставление с образцом; типы, встречающиеся в контексте конкретизации, запоминаются как Args
. Переменное множество параметров Args
называется пакетом параметров (parameter pack), а конструкция Args...
— расширением пакета.
Как и для обычных функций с переменным числом параметров, переменная часть может быть как пустым списком, так и содержать много элементов. Например, в конкретизации std::packaged_task
параметром ReturnType
является my_class
, а пакет параметров Args
пуст. С другой стороны, в конкретизации std::packaged_task
параметр ReturnType
— это void
, и Args
— список, состоящий из элементов int
, double
, my_class&
, std::string*
.
A.6.1. Расширение пакета параметров
Мощь шаблонов с переменным числом параметров связана с тем, что можно делать при расширении пакета, — мы отнюдь не ограничены простым расширением списка типов. Прежде всего, расширение пакета можно использовать всюду, где требуется список типов, например, в качестве списка аргументов другого шаблона:
Читать дальше