Этот раздел иллюстрирует основное использование этой библиотеки.
Локальные функции определяются с помощью макросов из файла заголовка<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;
}