Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

Tutorial

Boost , Chapter 1. Boost.LocalFunction 1.0.0 , Chapter 1. Boost.LocalFunction 1.0.0

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext

Этот раздел иллюстрирует основное использование этой библиотеки.

Локальные функции определяются с помощью макросов из файла заголовка<boost/local_function.hpp>. Макросы должны использоваться в декларативном контексте (это ограничение в отношениифункций лямбды C++11, которые вместо этого могут быть объявлены также в выражениях):

#include <boost/local_function.hpp> // This library header.
...
{ // Some declarative context.
    ...
    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) { // Local function.
    return x + y;
} BOOST_LOCAL_FUNCTION_NAME(add)
BOOST_TEST(add(1, 2) == 3); // Local function call.

Если локальная функция не имеет параметра, можно передать<void>на<BOOST_LOCAL_FUNCTION>макрос (аналогично синтаксису C++, который позволяет использовать<result-type function-name><(void)>для объявления функции без параметра):

BOOST_LOCAL_FUNCTION(void) // No parameter.

Например, запрограммируем локальную функцию, которая всегда возвращается<10>(см. также<ten_void.cpp>).:

int BOOST_LOCAL_FUNCTION(void) { // No parameter.
    return 10;
} BOOST_LOCAL_FUNCTION_NAME(ten)
BOOST_TEST(ten() == 10);

Переменные в объеме (локальные переменные, включающие параметры функции, элементы данных и т.д.) могут быть связаны с локальной декларацией функции. Только связанные переменные, статические переменные, глобальные переменные, функции и перечисления из области охвата доступны из локального функционального тела. Типы связанных переменных выводятся этой библиотекой автоматически с помощьюBoost.Typeof.

Эта библиотека вводит новое «ключевое слово»<bind>, который используется вместо типа параметра для указания названия переменной в области охвата для связывания (поэтому<bind>не может использоваться в качестве типа параметра локальной функции). Переменная может быть связана значением:

bind variable-name // Bind by value.

Или с помощью приставки переменного имени<&>:

bind& variable-name // Bind by reference.

Кроме того, «ключевое слово»<bind>может быть приставлено<const>для связывания переменной постоянным значением:

const bind variable-name // Bind by constant value.

Постоянная ссылка:

const bind& variable-name // Bind by constant value.

Обратите внимание, что когда<const>используется, он всегда должен предшествовать<bind><BOOST_LOCAL_FUNCTION>.

Если переменная связана значением, то копия переменного значения берется в точке локальной функциональной декларации. Если переменная связана ссылкой, переменная будет ссылаться на значение, которое она имеет в точке вызова локальной функции. Кроме того, ответственность программистов состоит в том, чтобы гарантировать, что переменные, связанные ссылкой, выдерживают существование области локальной функции, в противном случае связанные ссылки будут недействительны, когда локальная функция называется приводящей к неопределенному поведению (другими словами, обычная осторожность при использовании ссылок C++ должна быть взята для переменных, связанных ссылкой).

Тип связанной переменной автоматически выводится с использованиемBoost.Typeofи это тот же тип, который используется для объявления такой переменной в прилагаемой области с помощью следующих примечаний:

  • Если связанная переменная объявлена постоянной в приложенной области, она всегда будет связана постоянным значением или постоянной ссылкой, даже если вместо<constbind...>используется<bind...>. Однако, если связанная переменная не была объявлена постоянной в замкнутом пространстве, то она не будет связана как постоянная, если только постоянное связывание не будет вынуждено использовать<constbind...>. (Обратите внимание, что связывание посредством постоянной ссылки не поддерживаетсяC++11 лямбда-функциями, но поддерживается этой библиотекой.)<{... }>
  • Если связанная переменная была объявлена в качестве ссылки в прилагаемой области, она все равно будет связана значением, если она явно не связана ссылкой с использованием<bind&>или<constbind&>.<BOOST_LOCAL_FUNCTION>

Когда переменная связана величиной (постоянной или нет), ее тип должен быть<CopyConstructible>(т.е. она должна предоставить конструктор копий). Как и при передаче параметров обычным функциям C++, программисты могут захотеть связать переменные сложных типов (возможно, постоянными) ссылками вместо значения, чтобы избежать дорогостоящих операций копирования, когда эти переменные связаны с локальной функцией.

Например, запрограммируем локальную функцию<add>из примера в разделеВведение. Мы связываем локальную переменную<factor>постоянным значением (поскольку ее значение не должно изменяться локальной функцией), локальную переменную<sum>непостоянной ссылкой (поскольку ее значение должно обновляться с результатом суммирования) и программируем тело на выполнение суммирования (см. также<add.cpp>):

int main(void) {                            // Some local scope.
    int sum = 0, factor = 10;               // Variables in scope to bind.
    void BOOST_LOCAL_FUNCTION(const bind factor, bind& sum, int num) {
        sum += factor * num;
    } BOOST_LOCAL_FUNCTION_NAME(add)
    add(1);                                 // Call the local function.
    int nums[] = {2, 3};
    std::for_each(nums, nums + 2, add);     // Pass it to an algorithm.
    BOOST_TEST(sum == 60);                  // Assert final summation value.
    return boost::report_errors();
}

Также возможно связывать объект<this>, когда он находится в области (например, из замкнутой нестатической функции элемента). Это делается с помощью специального символа<this_>(вместо<this>) в качестве названия переменной для связывания в локальной функциональной декларации, а также для доступа к объекту внутри локального функционального тела.<BOOST_LOCAL_FUNCTION_NAME>

[Warning]Warning

Библиотека будет генерировать ошибку времени компиляции, если<this>ошибочно используется вместо<this_>для связывания объекта в локальной функциональной декларации. Однако ошибочное использование<this>вместо<this_>для доступа к объекту в локальном функциональном теле приведет к неопределенному поведению и не обязательно создаст ошибку времени компиляции.Программисты в конечном счете несут ответственность за то, чтобы<this>никогда не использовался в рамках локальной функции.

Объект<this>может быть связан значением:

bind this_ // Bind the object `this` by value.

В этом случае локальная функция будет иметь возможность модифицировать объект, когда область охвата не является постоянным членом, и она не сможет модифицировать объект, когда область охвата является постоянным членом. В противном случае объект<this>может быть связан постоянным значением:

const bind this_ // Bind the object `this` by constant value.

В этом случае локальная функция никогда не сможет модифицировать объект (независимо от того, является ли прилагаемый объем постоянным элементом или нет).

Обратите внимание, что объект<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; // Use `this_` instead of `this`.
        } 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> // This library header.
...
{ // Some declarative context within a template.
    ...
    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;
    // Must use the `..._TPL` macros within templates.
    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;
}



Обоснование.Имя локальной функции должно быть передано макросу<BOOST_LOCAL_FUNCTION_NAME>, заканчивающему определение функции, чтобы этот макрос мог объявить локальную переменную с именем локальной функции для удержания объекта локальной функции. Поэтому название локальной функции не может быть определено в<BOOST_LOCAL_FUNCTION>, и оно должно появиться вместо этого после тела локальной функции (даже если это отличается от обычного синтаксиса объявления функции C++).

156Обоснование.Если бы локальное функциональное тело было передано в качестве макропараметра, оно было бы расширено на одну строку кода (поскольку макросы всегда расширяются как одна строка кода). Таким образом, возможные номера строк ошибок компилятора будут сообщать одно и то же значение и больше не будут полезны для определения ошибок.

Обоснование.СтандартC++03не позволяет передавать пустые параметры на макрос, поэтому макрос не может быть вызван как<BOOST_LOCAL_FUNCTION()>. На компиляторахC99с правильно реализованной поддержкой пустых макропараметров можно было бы разрешить<BOOST_LOCAL_FUNCTION()>, но это уже не так для MSVC, поэтому этот синтаксис никогда не позволяет обеспечить лучшую переносимость.

Обоснование.Связывая переменную по объему, локальная декларация функций указывает, что такая переменная должна быть доступна в локальном функциональном органе независимо от его типа. Семантически это связывание следует рассматривать как «расширение» области охвата связанной переменной от области охвата до области охвата локального функционального органа. Следовательно, вопреки семантике прохождения параметра функции, семантика связывания переменной зависит не от типа переменной, а только от имени переменной: «Вариабельность в области, названнойx, должна быть доступна в пределах локальной функции, названнойf». Например, это уменьшает техническое обслуживание, поскольку при изменении связанного типа переменной локальная декларация функций не должна изменяться.

Очевидно, что токен<bind>не является ключевым словом языка C++. Эта библиотека анализирует токен<bind>во время макрорасширения с использованием препроцессорного метапрограммирования (см. разделРеализация). Поэтому<bind>можно считать новым «ключевым словом» только на уровне метапрограммирования препроцессора в пределах синтаксиса, определяемого макросами этой библиотеки (таким образом, его называют «ключевым словом» только в пределах цитат).

<BOOST_LOCAL_FUNCTION>Обоснование.Библиотечные макросы могли быть реализованы для принятия обоих синтаксисов<const bind...>и<bindconst ...>эквивалентно. Однако обработка обоих синтаксисов усложнила бы реализацию макроса без добавления какой-либо функции, поэтому поддерживается только один синтаксис<const bind...>.

<{... }>Непрерывное связывание переменных по объему было основным вариантом использования, который первоначально мотивировал авторов в разработке этой библиотеки. Авторы должны были локально создать код, чтобы утверждать некоторые условия корректности, в то время как эти утверждения не должны были изменять какие-либо из переменных, которые они использовали (см. библиотекуContract++). Это было достигнуто путем связывания посредством постоянной ссылки<constbind&>переменных, необходимых для утверждений, а затем путем программирования органа локальной функции для проверки утверждений. Таким образом, если какое-либо из утверждений ошибочно изменяет связанную переменную (например, смешивая оператора<==>с<=>), компилятор правильно генерирует ошибку, поскольку связанная переменная имеет тип<const>в локальном функциональном корпусе (см. такжепостоянные блокивПримерыраздела).

<BOOST_LOCAL_FUNCTION>Обоснование.Переменные, первоначально объявленные в качестве ссылок, связаны значением, если<[const]bind&>не используется, так что ссылки могут быть связаны как значением<[const]bind>, так и ссылкой<[const]bind&>(это та же семантика связывания, принятаяBoost.ScopeExit). Однако переменные, первоначально объявленные константами, никогда не должны терять свой<const>квалификатор (чтобы предотвратить их модификацию не только в замкнутой области, но и в локальной области), таким образом, они всегда связаны константой, даже если<bind[&]>используется вместо<constbind[&]>.

<BOOST_LOCAL_FUNCTION_NAME>Обоснование.Специальное имя<this_>было выбрано послеУскорить практику, чтобы исправить с помощью идентификаторов подчеркивания, которые названы в честь ключевых слов (ключевое слово C++<this>в этом случае). Специальный символ<this_>необходим, потому что<this>является зарезервированным ключевым словом C++, поэтому его нельзя использовать в качестве имени внутреннего параметра, который передает связанный объект в локальный функциональный корпус. Было бы возможно использовать<this>(вместо<this_>) в локальном функциональном корпусе либо за счет копирования связанного объекта (что ввело бы накладные расходы на время выполнения, а также строгое требование о том, что связанный объект должен иметь конструктор глубокой копии), либо полагаясь нанеопределенное поведение<static_cast>(которое может работать не на всех платформах за счет переносимости).

Обоснование.Местное функциональное тело не может быть статическим членом функции локального объекта функтора для поддержки рекурсии (поскольку локальное название функции указывается макро<BOOST_LOCAL_FUNCTION_NAME>только после тела, поэтому оно должно быть доступно через элемент данных функтора, названный в честь локальной функции, и местные классы не могут иметь статических членов данных в C++) и вложении (поскольку переменная связывания аргумента должна быть объявлена в качестве члена данных, чтобы она была видна в локальной функции, вложенной в функцию члена тела) - см. разделРеализация. Поэтому внутри тела локальной функции видима переменная<this>, но она относится к локальному функтору, а не к связанному объекту.

Обоснование.В шаблонах эта библиотека должна использовать<typename>, чтобы явно указать, что некоторые выражения оцениваются по типу. ПосколькуC++03не позволяет использовать<typename>внешние шаблоны, специальные<..._TPL>макросы используются для указания на то, что область охвата является шаблоном, поэтому эта библиотека может безопасно использовать<typename>для разрешения неясностей типа выражения.C++11и другие компиляторы могут компилировать локальные функции в шаблонах, даже если макросы<..._TPL>не используются. Тем не менее, рекомендуется всегда использовать макросы<..._TPL>в шаблонах для максимальной переносимости.


PrevUpHomeNext

Статья Tutorial раздела Chapter 1. Boost.LocalFunction 1.0.0 Chapter 1. Boost.LocalFunction 1.0.0 может быть полезна для разработчиков на c++ и boost.




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



:: Главная :: Chapter 1. Boost.LocalFunction 1.0.0 ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-07-05 01:42:38/0.0096390247344971/0