Этот раздел иллюстрирует основное использование этой библиотеки.
Локальные функции определяются с помощью макросов из файла заголовка<boost/local_function.hpp>. Макросы должны использоваться в декларативном контексте (это ограничение в отношениифункций лямбды C++11, которые вместо этого могут быть объявлены также в выражениях):
#include <boost/local_function.hpp>
...
{
...
result-type BOOST_LOCAL_FUNCTION(parameters) {
body-code
} BOOST_LOCAL_FUNCTION_NAME(name)
...
}
Расширенный макросами код объявляет объект функции (илифунктор) с указанием локального имени функции<BOOST_LOCAL_FUNCTION_NAME>.Обычные правила видимости области C++ применяются к локальным функциям, для которых локальная функция видна только в пределах области, в которой она объявлена.
Тип результата локальной функции указывается непосредственно перед макросом<BOOST_LOCAL_FUNCTION>.
Орган локальной функции задается с использованием обычного синтаксиса утверждения C++ в блоке кода<{...
}>между макросами<BOOST_LOCAL_FUNCTION>и<BOOST_LOCAL_FUNCTION_NAME>. Тело указывается вне любого из макросов, поэтому сообщения об ошибках компилятора и связанные номера строк сохраняют свое обычное значение и формат.
Параметры локальных функций передаются на макрос<BOOST_LOCAL_FUNCTION>в виде разделённого запятой списка токенов (см. разделNo Variadic Macrosдля компиляторов, которые не поддерживают вариадные макросы):
BOOST_LOCAL_FUNCTION(parameter-type1 parameter-name1, parameter-type2 parameter-name2, ...)
Максимальное количество параметров, которые могут быть переданы локальной функции, управляется в компиляционное время макроконфигурацией<BOOST_LOCAL_FUNCTION_CONFIG_ARITY_MAX>. Например, давайте запрограммируем локальную функцию под названием<add>, которая объединяет два целых числа<x>и<y>(см. также<add_params_only.cpp>):
int BOOST_LOCAL_FUNCTION(int x, int y) {
return x + y;
} BOOST_LOCAL_FUNCTION_NAME(add)
BOOST_TEST(add(1, 2) == 3);
Если локальная функция не имеет параметра, можно передать<void>на<BOOST_LOCAL_FUNCTION>макрос (аналогично синтаксису C++, который позволяет использовать<result-type
function-name><(void)>для объявления функции без параметра):
BOOST_LOCAL_FUNCTION(void)
Например, запрограммируем локальную функцию, которая всегда возвращается<10>(см. также<ten_void.cpp>).:
int BOOST_LOCAL_FUNCTION(void) {
return 10;
} BOOST_LOCAL_FUNCTION_NAME(ten)
BOOST_TEST(ten() == 10);
Переменные в объеме (локальные переменные, включающие параметры функции, элементы данных и т.д.) могут быть связаны с локальной декларацией функции. Только связанные переменные, статические переменные, глобальные переменные, функции и перечисления из области охвата доступны из локального функционального тела. Типы связанных переменных выводятся этой библиотекой автоматически с помощьюBoost.Typeof.
Эта библиотека вводит новое «ключевое слово»<bind>, который используется вместо типа параметра для указания названия переменной в области охвата для связывания (поэтому<bind>не может использоваться в качестве типа параметра локальной функции). Переменная может быть связана значением:
bind variable-name
Или с помощью приставки переменного имени<&>:
bind& variable-name
Кроме того, «ключевое слово»<bind>может быть приставлено<const>для связывания переменной постоянным значением:
const bind variable-name
Постоянная ссылка:
const bind& variable-name
Обратите внимание, что когда<const>используется, он всегда должен предшествовать<bind>.
Если переменная связана значением, то копия переменного значения берется в точке локальной функциональной декларации. Если переменная связана ссылкой, переменная будет ссылаться на значение, которое она имеет в точке вызова локальной функции. Кроме того, ответственность программистов состоит в том, чтобы гарантировать, что переменные, связанные ссылкой, выдерживают существование области локальной функции, в противном случае связанные ссылки будут недействительны, когда локальная функция называется приводящей к неопределенному поведению (другими словами, обычная осторожность при использовании ссылок C++ должна быть взята для переменных, связанных ссылкой).
Тип связанной переменной автоматически выводится с использованиемBoost.Typeofи это тот же тип, который используется для объявления такой переменной в прилагаемой области с помощью следующих примечаний:
- Если связанная переменная объявлена постоянной в приложенной области, она всегда будет связана постоянным значением или постоянной ссылкой, даже если вместо<
constbind...>используется<bind...>. Однако, если связанная переменная не была объявлена постоянной в замкнутом пространстве, то она не будет связана как постоянная, если только постоянное связывание не будет вынуждено использовать<constbind...>. (Обратите внимание, что связывание посредством постоянной ссылки не поддерживаетсяC++11 лямбда-функциями, но поддерживается этой библиотекой.) - Если связанная переменная была объявлена в качестве ссылки в прилагаемой области, она все равно будет связана значением, если она явно не связана ссылкой с использованием<
bind&>или<constbind&>.
Когда переменная связана величиной (постоянной или нет), ее тип должен быть<CopyConstructible>(т.е. она должна предоставить конструктор копий). Как и при передаче параметров обычным функциям C++, программисты могут захотеть связать переменные сложных типов (возможно, постоянными) ссылками вместо значения, чтобы избежать дорогостоящих операций копирования, когда эти переменные связаны с локальной функцией.
Например, запрограммируем локальную функцию<add>из примера в разделеВведение. Мы связываем локальную переменную<factor>постоянным значением (поскольку ее значение не должно изменяться локальной функцией), локальную переменную<sum>непостоянной ссылкой (поскольку ее значение должно обновляться с результатом суммирования) и программируем тело на выполнение суммирования (см. также<add.cpp>):
int main(void) {
int sum = 0, factor = 10;
void BOOST_LOCAL_FUNCTION(const bind factor, bind& sum, int num) {
sum += factor * num;
} BOOST_LOCAL_FUNCTION_NAME(add)
add(1);
int nums[] = {2, 3};
std::for_each(nums, nums + 2, add);
BOOST_TEST(sum == 60);
return boost::report_errors();
}
Также возможно связывать объект<this>, когда он находится в области (например, из замкнутой нестатической функции элемента). Это делается с помощью специального символа<this_>(вместо<this>) в качестве названия переменной для связывания в локальной функциональной декларации, а также для доступа к объекту внутри локального функционального тела.
![[Warning]](/img/warning.png) | Warning |
|---|
Библиотека будет генерировать ошибку времени компиляции, если<this>ошибочно используется вместо<this_>для связывания объекта в локальной функциональной декларации. Однако ошибочное использование<this>вместо<this_>для доступа к объекту в локальном функциональном теле приведет к неопределенному поведению и не обязательно создаст ошибку времени компиляции.Программисты в конечном счете несут ответственность за то, чтобы<this>никогда не использовался в рамках локальной функции. |
Объект<this>может быть связан значением:
bind this_
В этом случае локальная функция будет иметь возможность модифицировать объект, когда область охвата не является постоянным членом, и она не сможет модифицировать объект, когда область охвата является постоянным членом. В противном случае объект<this>может быть связан постоянным значением:
const bind this_
В этом случае локальная функция никогда не сможет модифицировать объект (независимо от того, является ли прилагаемый объем постоянным элементом или нет).
Обратите внимание, что объект<this>никогда не может быть связан ссылкой, потому что C++ не позволяет получить ссылку на<this>(библиотека будет генерировать ошибку времени компиляции, если программисты попытаются использовать<bind&this_>или<constbind&this_>). Обратите внимание, что<this>является указателем, поэтому заостренный объект никогда не копируется, даже если<this>связан значением (также невозможно напрямую связать<*this>, потому что<*this>является выражением, а не переменным именем).
Например, давайте запрограммируем локальную функцию<add>, аналогичную той, что приведена в примере из разделаВведение, но с использованием функции-члена для иллюстрации того, как связывать объект<this>(см. также<add_this.cpp>):
struct adder {
adder() : sum_(0) {}
int sum(const std::vector<int>& nums, const int factor = 10) {
void BOOST_LOCAL_FUNCTION(const bind factor, bind this_, int num) {
this_->sum_ += factor * num;
} BOOST_LOCAL_FUNCTION_NAME(add)
std::for_each(nums.begin(), nums.end(), add);
return sum_;
}
private:
int sum_;
};
Обратите внимание, что локальная функция имеет доступ ко всем членам класса через связанный объект<this_>независимо от их уровня доступа<public>,<protected>или<private>.В частности, в приведенном выше примере локальная функция обновляет частный элемент данных<sum_>.
Когда локальные функции программируются в шаблонах, они должны быть объявлены с помощью специальных макросов<BOOST_LOCAL_FUNCTION_TPL>и<BOOST_LOCAL_FUNCTION_NAME_TPL>:.
#include <boost/local_function.hpp>
...
{
...
result-type BOOST_LOCAL_FUNCTION_TPL(parameters) {
body-code
} BOOST_LOCAL_FUNCTION_NAME_TPL(name)
...
}
Макросы<BOOST_LOCAL_FUNCTION_TPL>и<BOOST_LOCAL_FUNCTION_NAME_TPL>имеют точно такой же синтаксис макросов<BOOST_LOCAL_FUNCTION>и<BOOST_LOCAL_FUNCTION_NAME>, который мы видели до сих пор.
Например, давайте запрограммируем локальную функцию, похожую на функцию из разделаВведение, но в шаблоне (см. также<add_template.cpp>):
template<typename T>
T total(const T& x, const T& y, const T& z) {
T sum = T(), factor = 10;
T BOOST_LOCAL_FUNCTION_TPL(const bind factor, bind& sum, T num) {
return sum += factor * num;
} BOOST_LOCAL_FUNCTION_NAME_TPL(add)
add(x);
T nums[2]; nums[0] = y; nums[1] = z;
std::for_each(nums, nums + 2, add);
return sum;
}