<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1252038906587337119</id><updated>2011-12-16T05:50:18.097+02:00</updated><category term='boost'/><category term='system'/><category term='COM'/><category term='VCS'/><category term='cpp'/><category term='WinAPI'/><category term='JScript'/><category term='IDE'/><category term='cpplib'/><category term='велосипед'/><title type='text'>Rakafon's blog</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://rakafon.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://rakafon.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Rakafon</name><uri>http://www.blogger.com/profile/03386514126069055282</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-wnns05XIxW4/Ti7XTMmujOI/AAAAAAAAABg/rZpn54sM7BI/s1600/20168127'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>23</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1252038906587337119.post-3569757509963969955</id><published>2010-06-06T15:50:00.001+03:00</published><updated>2011-06-10T03:15:11.688+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JScript'/><category scheme='http://www.blogger.com/atom/ns#' term='system'/><title type='text'>JScript: How to get AllUsers AppData directory</title><content type='html'>&lt;pre&gt;
var osXP = 0;
var osVista = 1;
var osWin7 = 2;

function getOsVersionString()
{
    var wbemFlagReturnImmediately = 0x10;
    var wbemFlagForwardOnly = 0x20;
    var objWMIService = GetObject("winmgmts:\\\\.\\root\\CIMV2");
    var colItems = objWMIService.ExecQuery("SELECT * FROM Win32_OperatingSystem", "WQL", wbemFlagReturnImmediately | wbemFlagForwardOnly);
    
    var enumItems = new Enumerator(colItems);
    var objItem = enumItems.item();
    
    return objItem.Caption;
}

function getOsVersion()
{
    var osVersionString = getOsVersionString();

    if (osVersionString.indexOf("Windows Vista") != -1)
    {
        return osVista;
    }

    if (osVersionString.indexOf("Windows 7") != -1)
    {
        return osWin7;
    }

    return osXP;
}

function getAllUsersAppData()
{
    var result;
    
    var wsShell = new ActiveXObject("WScript.Shell");
    result = wsShell.ExpandEnvironmentStrings("%ALLUSERSPROFILE%");
    
    try
    {
        var osVersion = getOsVersion();
        
        if (osVersion == osXP)
            result += "\\Application Data";
    }
    catch(err)
    {
    }

    return result;
}
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1252038906587337119-3569757509963969955?l=rakafon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rakafon.blogspot.com/feeds/3569757509963969955/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://rakafon.blogspot.com/2011/06/jscript-how-to-get-allusers-appdata.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/3569757509963969955'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/3569757509963969955'/><link rel='alternate' type='text/html' href='http://rakafon.blogspot.com/2011/06/jscript-how-to-get-allusers-appdata.html' title='JScript: How to get AllUsers AppData directory'/><author><name>Rakafon</name><uri>http://www.blogger.com/profile/03386514126069055282</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-wnns05XIxW4/Ti7XTMmujOI/AAAAAAAAABg/rZpn54sM7BI/s1600/20168127'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1252038906587337119.post-1284674907534878096</id><published>2009-04-02T01:01:00.010+03:00</published><updated>2010-10-29T12:09:19.149+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WinAPI'/><category scheme='http://www.blogger.com/atom/ns#' term='COM'/><category scheme='http://www.blogger.com/atom/ns#' term='system'/><title type='text'>Организация доступа к 32-bit DLL из 64-bit приложения.</title><content type='html'>&lt;p&gt;Перенос 32-битных Windows приложений на 64-битную машину может быть весьма проблематичным, если у вас есть 32-разрядные библиотеки DLL, которые вы не можете переписать и портировать для 64-bit. Майк Беккер покажет вам, как можно получить доступ к 32-bit DLL из 64-битного кода с помощью встроенных механизмов IPC.&lt;/p&gt;
&lt;p&gt;64-разрядные технологии Microsoft впервые появились в Windows Server 2003 для процессоров Itanium 2 (архитектура ихвестна как &amp;quot;IA64&amp;quot;) а также для &lt;span id="DocumentCopy"&gt;eXtended CPUs&lt;/span&gt; (архитектура известна как &amp;quot;x64&amp;quot;). 64-bit технология имеет много преимуществ, но также поднимает новые вопросы для разработчиков программного обеспечения. Например, вам может понадобиться необходимость доступа к существующим 32-разрядным библиотекам DLL из 64-битного процесса.&lt;/p&gt;
&lt;p&gt;Главное преимущество технологии 64-бит состоит в способности адресовать до 8 ТБ памяти, против максимальных 2 Гб для 32-битных процессов. Как результат, 64-разрядная технология позволяет проводить операции с большим объёмом данных в оперативной памяти без необходимости временного сброса памяти на жётский диск. Это может значительно повысить производительность и открыть новые алгоритмы обработки данных базирующихся на очень больших доступных объёмов оперативной памяти. Как бы то ни было аргументы для миграции существующего программного обеспечения на 64-битную платформу имеют место быть.&lt;/p&gt;
&lt;p&gt;Многие приложения, написанные с помощью C/C++ могут быть легко портированы под 64-битную платформу, особенно если они написаны в виде монолитного модуля. Иногда достаточно просто пересобрать исходные коды с использованием x64/IA64 компилятора. Однако уже опубликованное или базирующееся на модулях ПО может вызвать проблемы.&lt;/p&gt;

&lt;h4&gt;Конфликт: 64-bit против 32-bit&lt;/h4&gt;
&lt;p&gt;Основная проблема миграции возникает при необходимости портирования 32-разрядных программных компонентов, которые не могут быть пересобраны, возможно, потому что исходный код потерян, к нему нет доступа или одна из зависимостей этого модуля не можeт быть перенесена на 64-bit платформу.&lt;/p&gt;
&lt;p&gt;32-битное ПО по-прежнему поддерживается на 64-битной платформе. Так 32-битные процессы могут выполняться внутри Windows WOW64-подсистемы, которая является частью всех 64-битных систем Windows. Однако 64-разрядный процесс не может загружать 32-разрядные модули в своё адресное пространство, также и 32-разрядные процессы не могут загружать 64-разрядные модули в своё адресное пространство. Единственный способ общения между 32-битными и 64-битными модулями возможен путём межпроцессного взаимодействия (IPC). Другими словами, 32-разрядные и 64-разрядные процессы могут обмениваться данными с использованием IPC-механизмов, например такие как out-of-proc COM, сокеты, сообщения Windows или MMF (Memory mapped files).&lt;/p&gt;

&lt;img border="1" src="http://www.dnjonline.com/images/articles/technology/access3264_1.jpg" /&gt;

&lt;p&gt;Например, 32-битный программный продукт содержит основной модуль WeatherReport (см. рисунок выше), который внутри обращается к DLL WeatherStationControl. Пока основной модуль и DLL являются 32-разрядными, продукт может работать как на 32-битных, так и 64-битных платформах (внутри WOW64). Если основной модуль и DLL переносятся на 64-битную платформу, то они могут работать в рамках 64-битных процессов. Однако, если только основной модуль переносится на 64-bit, он не сможет загружать 32-разрядные DLL.&lt;/p&gt;

&lt;p&gt;Лучшим способом переноса такого продукта на 64-битную платформу является миграция как основного модуля, так и всех его зависимостей, но если хоть одна зависимая DLL не может быть перенесена, то продукт не может быть загружен в 64-битном процессе, следовательно приложение работать не будет.&lt;/p&gt;

&lt;h4&gt;Решение: суррогатный процесс&lt;/h4&gt;
&lt;p&gt;Эта проблема может быть решена путем загрузки зависимой 32-битной DLL в отдельном пространстве 32-разрядного процесса. Основной модуль, работая в качестве 64-битного процесса, может получить доступ к зависимым DLL'ям через границы процессов, используя IPC (&lt;a href="http://msdn2.microsoft.com/en-us/library/aa365574.aspx"&gt;Смотри MSDN reference&lt;/a&gt;).&lt;/p&gt;

&lt;img border="1" src="http://www.dnjonline.com/images/articles/technology/access3264_4.jpg" /&gt;

&lt;p&gt;64-битный процесс может получить доступ к 32-разрядной DLL используя механизмы межпроцессного взаимодействия. То бишь 32-разрядные DLL загружаются в отдельный 32-битный суррогатный процесс, и тогда 64-битное приложение использует встроенные механизмы IPC для того, чтобы обмениваться данными 32-битным процессом.&lt;/p&gt;
&lt;p&gt;Это решение требует дополнительной работы, например необходимо создать 32-разрядный суррогатный процесс, который загрузит 32-разрядные DLL и предоставит API для работы с ними. Кроме того, некоторые изменения будет необходимо стелать со стороны 64-битного клиента, т.к. клиент будет вынужден использовать методы IPC вместо непосредственного доступа к 32-разрядной DLL. Стоит отметить, что, в крайнем случае, эта дополнительная работа может быть сравнима с работой, которую необходимо выполнить при разработке 64-разрядной версию 32-битной DLL с нуля.&lt;/p&gt;
&lt;p&gt;Одним из возможных путей сокращения этих расходов является реализация 64-разрядной DLL обертки, которая предоставит те же функции, что и оригинальная 32-битная DLL. Эта обёртка уже внутри себя скроет детали IPC вызовов оригинальной 32-битной DLL, загруженной в 32-битный суррогатный процесс.&lt;/p&gt;

&lt;img border="1" src="http://www.dnjonline.com/images/articles/technology/access3264_5.jpg" /&gt;

&lt;p&gt;64-битная обёртка (WeatherStationControl64.DLL) экспортирует тот же интерфейс, что и оригинальная 32-битная DLL (WeatherStationControl.DLL), то бишь предоставляет главному модулю WeatherReport те же сервисы без необходимости внесения изменений в код модуля WeatherReport.&lt;/p&gt;
&lt;p&gt;Основные затраты этого решения связаны с реализацией суррогатного процесса, загружающего 32-битную DLL и реализаццей 64-битной DLL оболочки. Фактически затраты будут зависеть от того, какая из IPC технологий будет использоваться для обмена данными между 64-битным и 32-битным процессами.&lt;/p&gt;

&lt;h4&gt;Использование COM для межпроцессного взаимодействия&lt;/h4&gt;

&lt;p&gt;Один из самых популярных методов IPC - это DCOM (Distributed COM). Первоначально разработанная для распределенных систем, DCOM по-прежнему поддерживается как на 64-битных платформах Windows. Модули COM могут быть собраны как 32-разрядные так и 64-разрядные. Единственным ограничением является то, что 64-битные и 32-битные модули не могут находиться в одном и том же процессе, следовательно они должны взаимодействовать через границы процессов. Это делается с помощью out-of-process (OOP) COM компонентов, следующим образом:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Создаём 32-битный COM-Сервер, который загрузит 32-битную DLL и опубликует 32-bit DLL интерфейс как COM-интерфейс, реализованный внутри через делегирование к API исходной 32-битной DLL.&lt;/li&gt;
&lt;li&gt;Конфигурируем этот COM-Сервер для out-of-proc загрузки любым способом создания COM+ приложений (используя dllhost.exe в качестве суррогата).&lt;br/&gt;
Также можно реализовать этот COM-компонент как специальный COM-Сервер EXE, используя ATL COM Server в качестве хостящего процесса.&lt;br/&gt;
Можно также помеcтить этот COM-компонент внутрь Win32-сервиса.&lt;/li&gt;
&lt;li&gt;Создаём 64-разрядную DLL оболочку, реализующую тот же интерфейс, как оригинальная 32-битная DLL.
Обёртка будет импортировать COM-интерфейс из COM-объекта, созданного выше, и транслировать каждый API вызов в обращение к COM-интерфейсу, передавая параметры вызова и получая возвращаемые значения.&lt;/li&gt;
&lt;/ol&gt;

&lt;img border="1" src="http://www.dnjonline.com/images/articles/technology/access3264_6.jpg" /&gt;

&lt;p&gt;32-разрядная DLL (WeatherStationControl.DLL) используется СОМ-объектом (WeatherStationWrapper), который предоставляет интерфейс 32-битной DLL в качестве COM-интерфейса. 64-битная DLL обёртка (WeatherStationControl64.DLL) делает вызовы COM-интерфейса, которые уже делегируют всю работу оригинальным API вызовам исходной 32-битой DLL. Основной процесс (WeatherReport) использует интерфейс, предоставляемый 64-разрядной DLL обёрткой, но на самом деле работа выполняется в оригинальной 32-битной DLL.&lt;/p&gt;

&lt;p&gt;Это решение должно быть значительно дешевле, чем создание 64-разрядную версию 32-битных DLL с нуля. Библиотека ATL, поддерживающаяся Visual Studio, вкупе со всеми своими визардами и готовыми фрагментами кода, также должны помочь снизить затраты миграции за счет экономии времени и снижения вероятности ошибок.&lt;/p&gt;

&lt;h4&gt;Последствия&lt;/h4&gt;

&lt;p&gt;Однако существует ряд вещей, которые вам все еще нужно иметь в виду:&lt;/p&gt;

&lt;ol&gt;
    &lt;li&gt;&lt;strong&gt;Выравнивание&lt;br/&gt;&lt;/strong&gt;Выравнивание данных в памяти отличается в 32-bit и 64-bit процессах. Это означает, что более сложные пользовательские структуры данных могут быть сериализованы 32-разрядным процессом иначе, чем ожидается в 64-битном проыцессе, и наоборот. Microsoft Windows Platform SDK включает документацию о различиях в соответствие памяти данными между 32-битной и 64-битных процессов.&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Типы данных&lt;br/&gt;&lt;/strong&gt;В большинстве случаев, 64-разрядная Windows использует те же типы данных, как 32-битной версии. Различия в основном в указателях, которые 32-битные в 32-битной версий Windows и 64-битные в 64-битных Windows.&lt;br/&gt;Указатель полученных данных типов, таких как HANDLE и HWND также различны между 32-битной и 64-разрядных версиях. Windows позволяет вести единый базовый код для 32-разрядных версиях и 64-битного программного обеспечения, предлагая полиморфные типы данных, которые имеют различную длину в зависимости от целевой платформы, например INT_PTR представляет целое с таким же размером, как и указатель. Любая переменная этого типа будет целым числом, которое составляет 32 бита на 32-битной платформе и 64 бита на 64-битной платформе.&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;COM инициализации&lt;br/&gt;&lt;/strong&gt;Вы можете получить доступ к СОМ-объекту, если он был успешно инициализирован. Функция COM API CoInitialize() должна вызываться для каждого потока, который собирается работать с COM-объектом, т.е. делать вызовы COM-интерфейсов, также должна вызываться CoUninitialize() перед завершением потока.(&lt;a href="http://msdn2.microsoft.com/en-us/library/ms678543.aspx"&gt;см. MSDN&lt;/a&gt;). Это правило должно строго соблюдаться, если основной процесс вызывает оригинальные 32-битные DLL из разных потоков выполнения.&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Безопасность&lt;br/&gt;&lt;/strong&gt;При использовании out-of-proc, экземпляры COM-объектов находятся в отдельном процессе, независимо от того используете вы стандартный суррогатной процесс, EXE COM-Сервер или Win32 сервис. Это может означать, что вызовы 32-битной DLL могут произойти в другом контексте безопасности, чем у основного процесса, особенно если основной процесс интенсивно использует имперсонирование. Если это так, вы можете настроить собственные параметры доступа для out-of-proc компонента, или осуществлять внутреннее имперсонирование внутри COM-объекта.&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Производительность&lt;br/&gt;&lt;/strong&gt;IPC-решение почти наверняка будет медленнее, чем прямые вызовы DLL. Маршалинг данных за границы процессов, автоматическое преобразование данных между 32 и 64 бит, WOW64 особенности, задержки инстанцирования экземпляров COM-объектов - всё это будет влиять на производительность. Однако есть много методов оптимизации, которые можно использовать, таких как COM pooling, кэширование данных внутри DLL-оболочки, реализация критичных к производительности интерфейсов в 64-битной DLL, и так далее.&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Перенаправление&lt;br/&gt;&lt;/strong&gt;Подсистема WOW64 отвечает за поддержку 32-битных модулей на 64-битных Windows. Чтобы избежать нежелательных коллизий между 32-битным и 64-битным ПО, особенно при доступе к файловой системы и реестру, WOW64 изолирует 32-разрядные модули, используя механизм, называемый перенаправление (см. &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/win64/win64/running_32_bit_applications.asp"&gt;MSDN&lt;/a&gt;).&lt;br/&gt;Например, для 64-битного процесса при получении пути системной папки возвращается %WINDOWS%\System32, а для 32-разрядного процесса возвращается %WINDOWS%\SysWOW64.&lt;br/&gt;Путь к папке исполняемого файла будет &amp;quot;Program Files&amp;quot; для 64-битного процесса, но для 32-разрядного процесса это будет &amp;quot;Program Files (x86)&amp;quot;.&lt;br/&gt;Раздел реестра HKEY_LOCAL_MACHINE\Software содержит настройки и данные для 64-разрядных процессов, а ключ HKEY_LOCAL_MACHINE\Software\WOW6432Node содержит настройки и данные для 32-разрядных процессов.&lt;br/&gt;Это перенаправление активируется автоматически, когда программные модули пытаются получить предопределённые системные пути или ключи реестра.&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Модули ядра&lt;br/&gt;&lt;/strong&gt;Предложенное здесь решение работает для 32-разрядных DLL, использующихся в user mode, но не работает с 32-битными драйверами. Это происходит, потому что 32-битные модули ядра не могут быть использованы на 64-битной платформе, без исключений или обходных путей. Если ваш продукт включает в себя любой модуль уровня ядра, таких как драйвер устройства, то единственно возможный путь миграции - это портировать модуль ядра на 64-битную платформу.&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Установка.&lt;br/&gt;&lt;/strong&gt;Использование out-of-proc COM-компонента требует изменений в процедуре установки вашего ПО, т.к. COM-компонент должен быть установлен и зарегистрирован в системе. Как уже говорилось выше в пункте Безопасность, для этого может потребоваться настройка специальных параметров доступа для COM-компонента.&lt;/li&gt;
&lt;/ol&gt;

&lt;a href="http://www.dnjonline.com/files/32to64.zip"&gt;Тыкните сюда дабы скачать пример кода&lt;/a&gt;

&lt;hr width="30%" align="left" /&gt;

&lt;p&gt;Оригинал статьи здесь: &lt;a href="http://www.dnjonline.com/article.aspx?id=jun07_access3264"&gt;Mike Becker: "Accessing 32-bit DLLs from 64-bit code", Jun 2007&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Литература:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/Aa384249"&gt;Running 32-bit Applications&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.microsoft.com/whdc/system/platform/64bit/WoW64_bestprac.mspx"&gt;Best Practices for WOW64&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn2.microsoft.com/en-us/library/aa365574.aspx"&gt;MSDN on Interprocess Communications&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn2.microsoft.com/en-us/library/ms952405.aspx"&gt;Introduction to Developing Applications for the 64-bit Itanium-based Version of Windows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn2.microsoft.com/en-us/library/ms678543.aspx"&gt;Understanding CoInitialize()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/win64/win64/running_32_bit_applications.asp"&gt;Running 32-bit applications on 64-bit Windows (including information on Redirection)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.rsdn.ru/forum/dotnet/1992529.flat.aspx"&gt;x32 unmanaged dll из x64 managed dll C++ 2.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.rsdn.ru/forum/dotnet/3616207.flat.aspx"&gt;Как в 64-bit приложение загрузить 32-bit dll
&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1252038906587337119-1284674907534878096?l=rakafon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rakafon.blogspot.com/feeds/1284674907534878096/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://rakafon.blogspot.com/2009/04/32-bit-dll-64-bit.html#comment-form' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/1284674907534878096'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/1284674907534878096'/><link rel='alternate' type='text/html' href='http://rakafon.blogspot.com/2009/04/32-bit-dll-64-bit.html' title='Организация доступа к 32-bit DLL из 64-bit приложения.'/><author><name>Rakafon</name><uri>http://www.blogger.com/profile/03386514126069055282</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-wnns05XIxW4/Ti7XTMmujOI/AAAAAAAAABg/rZpn54sM7BI/s1600/20168127'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1252038906587337119.post-8676037255782727623</id><published>2009-04-01T23:15:00.001+03:00</published><updated>2010-10-15T13:57:57.634+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='велосипед'/><category scheme='http://www.blogger.com/atom/ns#' term='cpp'/><title type='text'>Base64 Encoder</title><content type='html'>&lt;h2&gt;Велосипед отечественного производства для кодирования бинарных данных в текст с кодировкой Base64 и обратно.&lt;/h2&gt;&lt;lj-cut&gt; &lt;span style="font-size: medium;"&gt;&lt;strong&gt;Файл check_helpers.hpp&lt;/strong&gt;&lt;/span&gt; &lt;pre&gt;//------------------------------------------------------------------------
#ifndef __CHERCKHELPERS_HEADER_INCLUDED__
#define __CHERCKHELPERS_HEADER_INCLUDED__
//------------------------------------------------------------------------
#include &amp;lt;boost/type_traits.hpp&amp;gt;
//------------------------------------------------------------------------
template&amp;lt;class IterTypeT&amp;gt;
struct IsRandomAccesIterator
{
    static const bool value = false;
};
template&amp;lt;&amp;gt;
struct IsRandomAccesIterator&amp;lt;std::random_access_iterator_tag&amp;gt;
{
    static const bool value = true;
};
//------------------------------------------------------------------------
#define CHARTYPE_SOURCE_SEQUENCE_CHECK(stl_container_t) \
    BOOST_STATIC_ASSERT ( \
    boost::is_fundamental&amp;lt;typename stl_container_t::value_type&amp;gt;::value ); \
    BOOST_STATIC_ASSERT ( \
    sizeof(typename stl_container_t::value_type) == static_cast&amp;lt;std::size_t&amp;gt;(1) );
//------------------------------------------------------------------------
#define CHARTYPE_SOURCE_ITERATOR_CHECK(iterator_t) \
    BOOST_STATIC_ASSERT ( \
        boost::is_fundamental&amp;lt;typename std::iterator_traits&amp;lt;iterator_t&amp;gt;::value_type&amp;gt;::value ); \
    BOOST_STATIC_ASSERT ( \
        sizeof(typename std::iterator_traits&amp;lt;iterator_t&amp;gt;::value_type) == static_cast&amp;lt;std::size_t&amp;gt;(1) );
//------------------------------------------------------------------------
#define RANDOM_ACCESS_ITERATOR_CHECK(iterator_t) \
    BOOST_STATIC_ASSERT ( \
    IsRandomAccesIterator&amp;lt; \
        typename std::iterator_traits&amp;lt;iterator_t&amp;gt;::iterator_category&amp;gt;::value );
//------------------------------------------------------------------------
//------------------------------------------------------------------------
#endif // __CHERCKHELPERS_HEADER_INCLUDED__
//------------------------------------------------------------------------

&lt;/pre&gt;&lt;strong&gt;&lt;span style="font-size: medium;"&gt;Файл base64_conv.h&lt;/span&gt;&lt;/strong&gt; &lt;pre&gt;//------------------------------------------------------------------------
#ifndef __BASE64_CONVERTER_HEADER_INCLUDED__
#define __BASE64_CONVERTER_HEADER_INCLUDED__
//------------------------------------------------------------------------
#include &amp;lt;boost/noncopyable.hpp&amp;gt;
#include &amp;lt;boost/shared_ptr.hpp&amp;gt;
#include &amp;lt;boost/type_traits.hpp&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;string&amp;gt;
#include &amp;lt;iterator&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;quot;check_helpers.hpp&amp;quot;
//------------------------------------------------------------------------
class base64_conv : private boost::noncopyable
{
public:
    typedef std::vector&amp;lt;char&amp;gt;           buffer_t;
    typedef boost::shared_ptr&amp;lt;buffer_t&amp;gt; p_buffer_t;

public:
    base64_conv();
    ~base64_conv();

    template&amp;lt;typename stl_container_t&amp;gt;
    void to_base64 ( const stl_container_t &amp;amp; sourse_data )
    {
        // This code can not be compiled, because a sequence is contained
        // by a wrong type; need sequence which contained by predefined char type
        CHARTYPE_SOURCE_SEQUENCE_CHECK(stl_container_t);

        std::vector&amp;lt;typename stl_container_t::value_type&amp;gt; tmp_buffer (
            sourse_data.begin(), sourse_data.end() );
        to_base64(tmp_buffer);
    }
    
    template&amp;lt;typename char_t, typename allocator_t&amp;gt;
    void to_base64 (
        const std::vector&amp;lt;char_t, allocator_t&amp;gt; &amp;amp; sourse_data )
    {
        if ( sourse_data.empty() )
        {
            p_buffer-&amp;gt;clear();
            return;
        }

        to_base64_for_vector_or_string ( sourse_data.begin(), sourse_data.end() );
    }

    template&amp;lt;typename char_t, typename char_traits_t, typename allocator_t&amp;gt;
    void to_base64(
        const std::basic_string&amp;lt;char_t, char_traits_t, allocator_t&amp;gt; &amp;amp; sourse_data )
    {
        if ( sourse_data.empty() )
        {
            p_buffer-&amp;gt;clear();
            return;
        }

        to_base64_for_vector_or_string ( sourse_data.begin(), sourse_data.end() );
    }

    template&amp;lt;typename stl_container_t&amp;gt;
    void from_base64( const stl_container_t &amp;amp; sourse_data )
    {
        // This code can not be compiled, because a sequence is contained
        // by a wrong type; need sequence which contained by predefined char type
        CHARTYPE_SOURCE_SEQUENCE_CHECK(stl_container_t);

        std::vector&amp;lt;typename stl_container_t::value_type&amp;gt; tmp_buffer (
            sourse_data.begin(), sourse_data.end() );
        from_base64(tmp_buffer);
    }

    template&amp;lt;typename char_t, typename allocator_t&amp;gt;
    void from_base64 (
        const std::vector&amp;lt;char_t, allocator_t&amp;gt; &amp;amp; sourse_data )
    {
        if ( sourse_data.empty() )
        {
            p_buffer-&amp;gt;clear();
            return;
        }

        from_base64_for_vector_or_string (
            sourse_data.begin(), sourse_data.end() );
    }

    template&amp;lt;typename char_t, typename char_traits_t, typename allocator_t&amp;gt;
    void from_base64 (
        const std::basic_string&amp;lt;char_t, char_traits_t, allocator_t&amp;gt; &amp;amp; sourse_data )
    {
        if ( sourse_data.empty() )
        {
            p_buffer-&amp;gt;clear();
            return;
        }

        from_base64_for_vector_or_string (
            sourse_data.begin(), sourse_data.end() );
    }

    p_buffer_t get_result();
    void get_result ( std::string &amp;amp; out_str );
    void get_result ( std::vector&amp;lt;char&amp;gt; &amp;amp; out_buffer );

private:
    template&amp;lt;typename in_rait_t&amp;gt;
    void to_base64_for_vector_or_string (
        const in_rait_t it_begin, const in_rait_t it_end )
    {
        // This code can not be compiled, because a sequence is contained
        // by a wrong type; need sequence which contained by predefined char type
        CHARTYPE_SOURCE_ITERATOR_CHECK(in_rait_t);

        // This code can not be compiled, because iterator_category of in_rait_t
        // is not equal std::random_access_iterator_tag
        RANDOM_ACCESS_ITERATOR_CHECK(in_rait_t);

        std::size_t data_length = std::distance(it_begin, it_end);
        if ( data_length &amp;lt;= 0 )
        {
            p_buffer-&amp;gt;clear();
            return;
        }

        const char * p_data_begin = reinterpret_cast&amp;lt;const char*&amp;gt;( &amp;amp; * it_begin );
        do_encode_to_base64 ( p_data_begin, data_length );
    }

    template&amp;lt;typename in_rait_t&amp;gt;
    void from_base64_for_vector_or_string (
        const in_rait_t it_begin, const in_rait_t it_end )
    {
        // This code can not be compiled, because a sequence is contained
        // by a wrong type; need sequence which contained by predefined char type
        CHARTYPE_SOURCE_ITERATOR_CHECK(in_rait_t);

        // This code can not be compiled, because iterator_category of in_rait_t
        // is not equal std::random_access_iterator_tag
        RANDOM_ACCESS_ITERATOR_CHECK(in_rait_t);

        std::size_t data_length = std::distance(it_begin, it_end);
        if ( data_length &amp;lt;= 0 )
        {
            p_buffer-&amp;gt;clear();
            return;
        }

        const char * p_data_begin = reinterpret_cast&amp;lt;const char*&amp;gt;( &amp;amp; * it_begin );
        do_decode_from_base64 ( p_data_begin, data_length );
    }

    void do_encode_to_base64 (
        const char * sourse_data,
        std::size_t sourse_data_size );

    void do_decode_from_base64 (
        const char * sourse_data,
        std::size_t sourse_data_size );

private:
    enum { MAX_LINE_LENGTH = 72 };
    p_buffer_t p_buffer;
};
//------------------------------------------------------------------------
#endif // __BASE64_CONVERTER_HEADER_INCLUDED__
//------------------------------------------------------------------------

&lt;/pre&gt;&lt;span style="font-size: medium;"&gt;&lt;strong&gt;Файл base64_conv.cpp&lt;/strong&gt;&lt;/span&gt; &lt;pre&gt;//------------------------------------------------------------------------
#include &amp;quot;stdafx.h&amp;quot;
#include &amp;quot;base64_conv.h&amp;quot;
//------------------------------------------------------------------------
namespace {

// Translation Table as described in RFC1113
//------------------------------------------------------------------------
const char cb64[]=&amp;quot;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/&amp;quot;;

// Translation Table to decode (created by author)
//------------------------------------------------------------------------
const char cd64[]=&amp;quot;|$$$}rstuvwxyz{$$$$$$$&amp;gt;?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq&amp;quot;;

// encode 3 8-bit binary bytes as 4 '6-bit' characters
//------------------------------------------------------------------------
void encodeblock ( unsigned char in[3], unsigned char out[4], int len )
{
    out[0] = cb64[ in[0] &amp;gt;&amp;gt; 2 ];
    out[1] = cb64[ ((in[0] &amp;amp; 0x03) &amp;lt;&amp;lt; 4) | ((in[1] &amp;amp; 0xf0) &amp;gt;&amp;gt; 4) ];
    out[2] = (unsigned char) (len &amp;gt; 1 ? cb64[ ((in[1] &amp;amp; 0x0f) &amp;lt;&amp;lt; 2) | ((in[2] &amp;amp; 0xc0) &amp;gt;&amp;gt; 6) ] : '=');
    out[3] = (unsigned char) (len &amp;gt; 2 ? cb64[ in[2] &amp;amp; 0x3f ] : '=');
}

// decode 4 '6-bit' characters into 3 8-bit binary bytes
//------------------------------------------------------------------------
void decodeblock( unsigned char in[4], unsigned char out[3] )
{   
    out[ 0 ] = (unsigned char ) (in[0] &amp;lt;&amp;lt; 2 | in[1] &amp;gt;&amp;gt; 4);
    out[ 1 ] = (unsigned char ) (in[1] &amp;lt;&amp;lt; 4 | in[2] &amp;gt;&amp;gt; 2);
    out[ 2 ] = (unsigned char ) (((in[2] &amp;lt;&amp;lt; 6) &amp;amp; 0xc0) | in[3]);
}

// base64 encode a sequence adding padding and line breaks as per spec.
//------------------------------------------------------------------------
void encode (
    const char * in_sequence,
    std::size_t in_length,
    std::vector&amp;lt;char&amp;gt; &amp;amp; out_sequence,
    int line_size )
{
    unsigned char in[3], out[4];
    int i, len, blocks_out = 0;

    out_sequence.clear();
    out_sequence.reserve(in_length * 4/3);

    const char * it_begin   = in_sequence;
    const char * it_end     = in_sequence + in_length;

    while ( it_begin &amp;lt; it_end )
    {
        len = 0;
        for ( i = 0; i &amp;lt; 3; i++ )
        {
            if ( it_begin &amp;lt; it_end )
            {
                in[i] = static_cast&amp;lt;unsigned char&amp;gt;(*it_begin++);
                len++;
            }
            else
            {
                in[i] = 0;
            }
        }
        if ( len )
        {
            encodeblock( in, out, len );
            for( i = 0; i &amp;lt; 4; i++ )
            {
                out_sequence.push_back(out[i]);
            }
            blocks_out++;
        }
        if ( blocks_out &amp;gt;= (line_size/4) || ( it_begin == it_end ) )
        {
            if ( blocks_out )
            {
                out_sequence.push_back('\r');
                out_sequence.push_back('\n');
            }
            blocks_out = 0;
        }
    }
}

// decode a base64 encoded sequence discarding padding, line breaks and noise
//------------------------------------------------------------------------
void decode (
    const char * in_sequence,
    std::size_t in_length,
    std::vector&amp;lt;char&amp;gt; &amp;amp; out_sequence )
{
    unsigned char in[4], out[3], v;
    int i, len;

    out_sequence.clear();
    out_sequence.reserve(in_length * 3/4);

    const char * it_begin   = in_sequence;
    const char * it_end     = in_sequence + in_length;

    while( it_begin &amp;lt; it_end )
    {
        for( len = 0, i = 0; i &amp;lt; 4 &amp;amp;&amp;amp; (it_begin &amp;lt; it_end); i++ )
        {
            v = 0;
            for ( ; (it_begin &amp;lt; it_end) &amp;amp;&amp;amp; v == 0 ; ++it_begin )
            {
                v = static_cast&amp;lt;unsigned char&amp;gt;(*it_begin);
                v = static_cast&amp;lt;unsigned char&amp;gt;((v &amp;lt; 43 || v &amp;gt; 122) ? 0 : cd64[ v - 43 ]);
                if( v )
                {
                    v = static_cast&amp;lt;unsigned char&amp;gt;((v == '$') ? 0 : v - 61);
                }
            }
            if ( v )
            {
                len++;
                in[i] = static_cast&amp;lt;unsigned char&amp;gt;(v - 1);
            }
            else
            {
                in[i] = 0;
            }
        }
        if( len )
        {
            decodeblock( in, out );
            for( i = 0; i &amp;lt; len - 1; i++ )
            {
                out_sequence.push_back(out[i]);
            }
        }
    }
}

}
//------------------------------------------------------------------------
base64_conv::base64_conv()
    : p_buffer ( new std::vector&amp;lt;char&amp;gt; )
{
};
//------------------------------------------------------------------------
base64_conv::~base64_conv()
{
};
//------------------------------------------------------------------------
void base64_conv::do_encode_to_base64 (
    const char * sourse_data, std::size_t sourse_data_size )
{
    encode ( sourse_data, sourse_data_size, *p_buffer, MAX_LINE_LENGTH );
}
//------------------------------------------------------------------------
void base64_conv::do_decode_from_base64 (
    const char * sourse_data, std::size_t sourse_data_size )
{
    decode ( sourse_data, sourse_data_size, *p_buffer );
}
//------------------------------------------------------------------------
base64_conv::p_buffer_t base64_conv::get_result()
{
    return p_buffer;
}
//------------------------------------------------------------------------
void base64_conv::get_result (
    std::string &amp;amp; out_str )
{
    std::string ret_val;
    ret_val.reserve(p_buffer-&amp;gt;size());
    std::copy (
        p_buffer-&amp;gt;begin(),
        p_buffer-&amp;gt;end(),
        std::back_inserter(ret_val) );
    std::swap(out_str, ret_val);
}
//------------------------------------------------------------------------
void base64_conv::get_result (
    std::vector&amp;lt;char&amp;gt; &amp;amp; out_buffer )
{
    std::swap(out_buffer, *p_buffer);
    p_buffer-&amp;gt;clear();
}
//------------------------------------------------------------------------

&lt;/pre&gt;&lt;/lj-cut&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1252038906587337119-8676037255782727623?l=rakafon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rakafon.blogspot.com/feeds/8676037255782727623/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://rakafon.blogspot.com/2009/04/base64-encoder.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/8676037255782727623'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/8676037255782727623'/><link rel='alternate' type='text/html' href='http://rakafon.blogspot.com/2009/04/base64-encoder.html' title='Base64 Encoder'/><author><name>Rakafon</name><uri>http://www.blogger.com/profile/03386514126069055282</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-wnns05XIxW4/Ti7XTMmujOI/AAAAAAAAABg/rZpn54sM7BI/s1600/20168127'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1252038906587337119.post-5996695384690498019</id><published>2009-04-01T22:20:00.001+03:00</published><updated>2010-10-15T14:00:15.486+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='boost'/><category scheme='http://www.blogger.com/atom/ns#' term='cpp'/><title type='text'>Использование boost::spirit</title><content type='html'>&lt;!-- Тело записи --&gt; В данной статье я расскажу как написать свой парсер ini-файлов на C++. За основу возьмём контекстно-свободную грамматику, построенную &lt;a href="http://avsmal.habrahabr.ru/blog/50973/"&gt;в предыдущей статье "Создаём парсер для ini-файлов. Теория"&lt;/a&gt;. Для построения парсера будет использоваться библиотека &lt;a href="http://spirit.sourceforge.net/"&gt;Boost Spirit&lt;/a&gt;, которая позволяет строить свои собственные парсеры комбинируя готовые &lt;i&gt;примитивные&lt;/i&gt; парсеры при помощи &lt;i&gt;парсерных комбинаторов&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Важно:&lt;/b&gt; в данной статье предполагается, что читатель знаком с основами C++ (в том числе будет активно использоваться STL). Если вы не очень в себе уверены, то я советую сначала прочитать пару статей для новичков по С++ и по STL.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;Грамматика&lt;/h2&gt;&lt;br /&gt;
Для начала вспомним какую грамматику для ini-фалов мы построили в предыдущей статье:&lt;br /&gt;
&lt;code&gt;inidata = spaces, {section} .&lt;br /&gt;
section = &amp;quot;[&amp;quot;, ident, &amp;quot;]&amp;quot;, stringSpaces, &amp;quot;\n&amp;quot;, {entry} .&lt;br /&gt;
entry = ident, stringSpaces, &amp;quot;=&amp;quot;, stringSpaces, value, &amp;quot;\n&amp;quot;, spaces .&lt;br /&gt;
ident = identChar, {identChar} .&lt;br /&gt;
identChar = letter | digit | &amp;quot;_&amp;quot; | &amp;quot;.&amp;quot; | &amp;quot;,&amp;quot; | &amp;quot;:&amp;quot; | &amp;quot;(&amp;quot; | &amp;quot;)&amp;quot; | &amp;quot;{&amp;quot; | &amp;quot;}&amp;quot; | &amp;quot;-&amp;quot; | &amp;quot;#&amp;quot; | &amp;quot;@&amp;quot; | &amp;quot;&amp;&amp;quot; | &amp;quot;*&amp;quot; | &amp;quot;|&amp;quot; .&lt;br /&gt;
value = {not &amp;quot;\n&amp;quot;} .&lt;br /&gt;
stringSpaces = {&amp;quot; &amp;quot; | &amp;quot;\t&amp;quot;} .&lt;br /&gt;
spaces = {&amp;quot; &amp;quot; | &amp;quot;\t&amp;quot; | &amp;quot;\n&amp;quot; | &amp;quot;\r&amp;quot;} .&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
Её описание нам скоро понадобится.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;C++ и Boost Spirit&lt;/h2&gt;&lt;br /&gt;
&lt;br /&gt;
Начните с установки boost (можно взять на официальном сайте или поискать готовые пакеты для вашей OS). Собирать boost не требуется, так как весь Spirit живёт в хедерах. Процесс установки для разных систем может быть различным, поэтому я не буду его здесь описывать.&lt;br /&gt;
&lt;br /&gt;
Я постараюсь подробно описать процесс создания парсера на С++. При этом я не буду особенно думать о производительности, так как это не является целью данной статьи. &lt;br /&gt;
&lt;br /&gt;
Начнём с подключения необходимых хедеров. &lt;br /&gt;
&lt;code&gt;   1 &lt;font color="#ff6060"&gt;&lt;b&gt;#include &lt;/b&gt;&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;lt;fstream&amp;gt;&lt;/font&gt;&lt;br /&gt;
2 &lt;font color="#ff6060"&gt;&lt;b&gt;#include &lt;/b&gt;&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;lt;functional&amp;gt;&lt;/font&gt;&lt;br /&gt;
3 &lt;font color="#ff6060"&gt;&lt;b&gt;#include &lt;/b&gt;&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;lt;numeric&amp;gt;&lt;/font&gt;&lt;br /&gt;
4 &lt;font color="#ff6060"&gt;&lt;b&gt;#include &lt;/b&gt;&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;lt;list&amp;gt;&lt;/font&gt;&lt;br /&gt;
5 &lt;font color="#ff6060"&gt;&lt;b&gt;#include &lt;/b&gt;&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;lt;vector&amp;gt;&lt;/font&gt;&lt;br /&gt;
6 &lt;font color="#ff6060"&gt;&lt;b&gt;#include &lt;/b&gt;&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;lt;string&amp;gt;&lt;/font&gt;&lt;br /&gt;
7 &lt;br /&gt;
8 &lt;font color="#ff6060"&gt;&lt;b&gt;#include &lt;/b&gt;&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;lt;boost/spirit.hpp&amp;gt;&lt;/font&gt;&lt;br /&gt;
9 &lt;font color="#ff6060"&gt;&lt;b&gt;#include &lt;/b&gt;&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;lt;boost/algorithm/string.hpp&amp;gt;&lt;/font&gt;&lt;br /&gt;
10 &lt;br /&gt;
11 &lt;font color="#8080ff"&gt;&lt;b&gt;using&lt;/b&gt;&lt;/font&gt; &lt;font color="#00ff00"&gt;&lt;b&gt;namespace&lt;/b&gt;&lt;/font&gt; std;&lt;br /&gt;
12 &lt;font color="#8080ff"&gt;&lt;b&gt;using&lt;/b&gt;&lt;/font&gt; &lt;font color="#00ff00"&gt;&lt;b&gt;namespace&lt;/b&gt;&lt;/font&gt; boost::spirit;&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
Кроме хедера самого Spirit я включил библиотеку строчных алгоритмов из boost-а (буду использовать функцию trim). Конструкция using namespace не всегда является хорошей практикой, но здесь для краткости я себе это позволю.&lt;br /&gt;
&lt;br /&gt;
Определим типы данных: запись — это пара «ключ — значение», секция — это пара «ключ — список записей», все данные ini-файла — это список секций.&lt;br /&gt;
&lt;code&gt;  14 &lt;font color="#00ff00"&gt;&lt;b&gt;typedef&lt;/b&gt;&lt;/font&gt;  pair&amp;lt;string, string&amp;gt;    Entry;&lt;br /&gt;
15 &lt;font color="#00ff00"&gt;&lt;b&gt;typedef&lt;/b&gt;&lt;/font&gt;  list&amp;lt;Entry &amp;gt;            Entries;&lt;br /&gt;
16 &lt;font color="#00ff00"&gt;&lt;b&gt;typedef&lt;/b&gt;&lt;/font&gt;  pair&amp;lt;string, Entries&amp;gt;   Section;&lt;br /&gt;
17 &lt;font color="#00ff00"&gt;&lt;b&gt;typedef&lt;/b&gt;&lt;/font&gt;  list&amp;lt;Section&amp;gt;           IniData;&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
Кроме типов данных нам потребуются обработчики событий, которые будут вызываться в тот момент, когда парсер разберёт очередной нетерминал.&lt;br /&gt;
&lt;code&gt;  19 &lt;font color="#00ff00"&gt;&lt;b&gt;struct&lt;/b&gt;&lt;/font&gt; add_section&lt;br /&gt;
20 {&lt;br /&gt;
21    add_section( IniData &amp; data ) : data_(data) {}&lt;br /&gt;
22 &lt;br /&gt;
23    &lt;font color="#00ff00"&gt;void&lt;/font&gt; &lt;font color="#ff6060"&gt;&lt;b&gt;operator&lt;/b&gt;&lt;/font&gt;()(&lt;font color="#00ff00"&gt;char&lt;/font&gt; &lt;font color="#00ff00"&gt;const&lt;/font&gt;* p, &lt;font color="#00ff00"&gt;char&lt;/font&gt; &lt;font color="#00ff00"&gt;const&lt;/font&gt;* q) &lt;font color="#00ff00"&gt;const&lt;/font&gt;&lt;br /&gt;
24    {&lt;br /&gt;
25       string s(p,q);&lt;br /&gt;
26       boost::algorithm::trim(s);&lt;br /&gt;
27       data_.push_back( Section( s, Entries() ) );&lt;br /&gt;
28    }&lt;br /&gt;
29 &lt;br /&gt;
30    IniData &amp; data_;&lt;br /&gt;
31 };&lt;br /&gt;
32 &lt;br /&gt;
33 &lt;font color="#00ff00"&gt;&lt;b&gt;struct&lt;/b&gt;&lt;/font&gt; add_key&lt;br /&gt;
34 {&lt;br /&gt;
35    add_key( IniData &amp; data ) : data_(data) {}&lt;br /&gt;
36 &lt;br /&gt;
37    &lt;font color="#00ff00"&gt;void&lt;/font&gt; &lt;font color="#ff6060"&gt;&lt;b&gt;operator&lt;/b&gt;&lt;/font&gt;()(&lt;font color="#00ff00"&gt;char&lt;/font&gt; &lt;font color="#00ff00"&gt;const&lt;/font&gt;* p, &lt;font color="#00ff00"&gt;char&lt;/font&gt; &lt;font color="#00ff00"&gt;const&lt;/font&gt;* q) &lt;font color="#00ff00"&gt;const&lt;/font&gt;&lt;br /&gt;
38    {&lt;br /&gt;
39       string s(p,q);&lt;br /&gt;
40       boost::algorithm::trim(s);&lt;br /&gt;
41       data_.back().second.push_back( Entry( s, string() ) );&lt;br /&gt;
42    }&lt;br /&gt;
43 &lt;br /&gt;
44    IniData &amp; data_;&lt;br /&gt;
45 };&lt;br /&gt;
46 &lt;br /&gt;
47 &lt;font color="#00ff00"&gt;&lt;b&gt;struct&lt;/b&gt;&lt;/font&gt; add_value&lt;br /&gt;
48 {&lt;br /&gt;
49    add_value( IniData &amp; data ) : data_(data) {}&lt;br /&gt;
50 &lt;br /&gt;
51    &lt;font color="#00ff00"&gt;void&lt;/font&gt; &lt;font color="#ff6060"&gt;&lt;b&gt;operator&lt;/b&gt;&lt;/font&gt;()(&lt;font color="#00ff00"&gt;char&lt;/font&gt; &lt;font color="#00ff00"&gt;const&lt;/font&gt;* p, &lt;font color="#00ff00"&gt;char&lt;/font&gt; &lt;font color="#00ff00"&gt;const&lt;/font&gt;* q) &lt;font color="#00ff00"&gt;const&lt;/font&gt;&lt;br /&gt;
52    {&lt;br /&gt;
53       data_.back().second.back().second.assign(p, q);&lt;br /&gt;
54    }&lt;br /&gt;
55 &lt;br /&gt;
56    IniData &amp; data_;&lt;br /&gt;
57 };&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
Обработчики событий представляют собой функторы, которые принимают на вход кусок строки (через два указателя).&lt;br /&gt;
Функтор add_section будет вызываться в тот момент, когда парсер распознает очередную секцию. В качестве параметра add_section получит имя этой секции. Функтор add_key будет вызван в тот момент, когда парсер распознает имя нового параметра. Функтор add_value будет вызван в тот момент, когда парсер распознает значение параметра. При помощи этих функторов организуется последовательное заполнение IniData: сначала добавляется пустая секция (add_section), потом в эту секцию кладется Entry с незаполненным значением (add_key), а потом это значение заполняется (add_value).&lt;br /&gt;
&lt;br /&gt;
Теперь будем переносить грамматику из нотации Бэкуса-Наура в C++. Для этого создаётся специальный класс inidata_parser.&lt;br /&gt;
&lt;code&gt;  59 &lt;font color="#00ff00"&gt;&lt;b&gt;struct&lt;/b&gt;&lt;/font&gt; inidata_parser : &lt;font color="#8080ff"&gt;&lt;b&gt;public&lt;/b&gt;&lt;/font&gt; grammar&amp;lt;inidata_parser&amp;gt;&lt;br /&gt;
60 {&lt;br /&gt;
61    inidata_parser(IniData &amp; data) : data_(data) {}&lt;br /&gt;
62 &lt;br /&gt;
63    &lt;font color="#00ff00"&gt;&lt;b&gt;template&lt;/b&gt;&lt;/font&gt; &amp;lt;&lt;font color="#00ff00"&gt;&lt;b&gt;typename&lt;/b&gt;&lt;/font&gt; ScannerT&amp;gt;&lt;br /&gt;
64    &lt;font color="#00ff00"&gt;&lt;b&gt;struct&lt;/b&gt;&lt;/font&gt; definition&lt;br /&gt;
65    {&lt;br /&gt;
66       rule&amp;lt;ScannerT&amp;gt; inidata, section, entry, ident, value, stringSpaces, spaces;&lt;br /&gt;
67 &lt;br /&gt;
68       rule&amp;lt;ScannerT&amp;gt; &lt;font color="#00ff00"&gt;const&lt;/font&gt;&amp; start() &lt;font color="#00ff00"&gt;const&lt;/font&gt; { &lt;font color="#8080ff"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; inidata; }&lt;br /&gt;
69 &lt;br /&gt;
70       definition(inidata_parser &lt;font color="#00ff00"&gt;const&lt;/font&gt;&amp; self)&lt;br /&gt;
71       {&lt;br /&gt;
72          inidata = *section;&lt;br /&gt;
73 &lt;br /&gt;
74          section = ch_p(&lt;font color="#0000ff"&gt;'['&lt;/font&gt;)&lt;br /&gt;
75                &amp;gt;&amp;gt; ident[add_section(self.data_)]&lt;br /&gt;
76                &amp;gt;&amp;gt; ch_p(&lt;font color="#0000ff"&gt;']'&lt;/font&gt;)&lt;br /&gt;
77                &amp;gt;&amp;gt; stringSpaces&lt;br /&gt;
78                &amp;gt;&amp;gt; ch_p(&lt;font color="#0000ff"&gt;'\n'&lt;/font&gt;)&lt;br /&gt;
79                &amp;gt;&amp;gt; spaces&lt;br /&gt;
80                &amp;gt;&amp;gt; *(entry);&lt;br /&gt;
81 &lt;br /&gt;
82          entry =  ident[add_key(self.data_)]&lt;br /&gt;
83                &amp;gt;&amp;gt; stringSpaces&lt;br /&gt;
84                &amp;gt;&amp;gt; ch_p(&lt;font color="#0000ff"&gt;'='&lt;/font&gt;)&lt;br /&gt;
85                &amp;gt;&amp;gt; stringSpaces&lt;br /&gt;
86                &amp;gt;&amp;gt; value[add_value(self.data_)]&lt;br /&gt;
87                &amp;gt;&amp;gt; spaces;&lt;br /&gt;
88 &lt;br /&gt;
89 &lt;br /&gt;
90          ident  = +(alnum_p | chset&amp;lt;&amp;gt;(&lt;font color="#0000ff"&gt;&amp;quot;-_.,:(){}#@&amp;*|&amp;quot;&lt;/font&gt;) );&lt;br /&gt;
91 &lt;br /&gt;
92          value = *(~ch_p(&lt;font color="#0000ff"&gt;'\n'&lt;/font&gt;));&lt;br /&gt;
93 &lt;br /&gt;
94          stringSpaces = *blank_p;&lt;br /&gt;
95 &lt;br /&gt;
96          spaces = *space_p;&lt;br /&gt;
97       }&lt;br /&gt;
98 &lt;br /&gt;
99    };&lt;br /&gt;
100 &lt;br /&gt;
101    IniData &amp; data_;&lt;br /&gt;
102 };&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
Этот класс инкапсулирует в себе всю грамматику. Разберёмся поподробнее. В строке 59 мы видим, что парсер наследуется от шаблонного класса grammar, используя crtp, — это необходимo для правильной работы Spirit-а. Парсер принимает в конструкторе ссылку на незаполненную IniData и сохраняет её (61). Внутри парсера нужно определить шаблонную структуру definition (63-64). У структуры definitionесть члены данных типа rule — это парсеры для каждого из нетерминалов нашей грамматики в форме Бэкуса-Наура (66). Необходимо определить функцию-член start, которая будет возвращать ссылку на главный нетерминал — inidata (68). &lt;br /&gt;
&lt;br /&gt;
В конструкторе definition мы описываем грамматику. Грамматика переписывается на C++ почти дословно. inidata состоит из нескольких секций (72) — это выражается звёздочкой (как замыкание Клини, но звёздочка слева). Секция начинается с квадратной скобки — для этого используется встроенный парсер ch_p, который парсит один символ. Вместо запятой из нотации Бэкуса-Наура используется оператор &amp;gt;&amp;gt;. В квадратных скобках после выражения пишется функтор-обработчик события (75, 82, 86). Символ &amp;quot;+&amp;quot; слева означает «хотя бы один», а &amp;quot;~&amp;quot; означает отрицание. alnum_p — встроенный парсер для букв и цифр. chset&amp;lt;&amp;gt; соответствует любому символу из строки (важно, что минус идёт первым, иначе он воспринимается как знак интервала, вроде «a-z»). blank_p соответствует пробельному символу в строке (пробел или табуляция), space_p соответствует любому пробельному символу (в т.ч. и переводу строки и возврату каретки).&lt;br /&gt;
&lt;br /&gt;
Отметим, что нетерминалы ident и identChar удалось слить в один благодаря оператору &amp;quot;+&amp;quot; — в нотации Бэкуса-Наура это было невозможно, т.к. там отсутствует подобное обозначение.&lt;br /&gt;
&lt;br /&gt;
С грамматикой всё. Осталось научиться удалять комментарии и искать значение в IniData. &lt;br /&gt;
Для удаления комментариев нам потребуется специальный функтор.&lt;br /&gt;
&lt;code&gt; 104 &lt;font color="#00ff00"&gt;&lt;b&gt;struct&lt;/b&gt;&lt;/font&gt; is_comment{ &lt;font color="#00ff00"&gt;bool&lt;/font&gt; &lt;font color="#ff6060"&gt;&lt;b&gt;operator&lt;/b&gt;&lt;/font&gt;()( string &lt;font color="#00ff00"&gt;const&lt;/font&gt;&amp; s ) &lt;font color="#00ff00"&gt;const&lt;/font&gt; { &lt;font color="#8080ff"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; s[] == &lt;font color="#0000ff"&gt;'\n'&lt;/font&gt; || s[] == &lt;font color="#0000ff"&gt;';'&lt;/font&gt;; } };&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
Теперь напишем функцию поиска в IniData.&lt;br /&gt;
&lt;code&gt; 106 &lt;font color="#00ff00"&gt;&lt;b&gt;struct&lt;/b&gt;&lt;/font&gt; first_is&lt;br /&gt;
107 {&lt;br /&gt;
108     first_is(std::string &lt;font color="#00ff00"&gt;const&lt;/font&gt;&amp; s) : s_(s) {}&lt;br /&gt;
109 &lt;br /&gt;
110     &lt;font color="#00ff00"&gt;&lt;b&gt;template&lt;/b&gt;&lt;/font&gt;&amp;lt; &lt;font color="#00ff00"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/font&gt; Pair &amp;gt;&lt;br /&gt;
111     &lt;font color="#00ff00"&gt;bool&lt;/font&gt; &lt;font color="#ff6060"&gt;&lt;b&gt;operator&lt;/b&gt;&lt;/font&gt;()(Pair &lt;font color="#00ff00"&gt;const&lt;/font&gt;&amp; p) &lt;font color="#00ff00"&gt;const&lt;/font&gt; { &lt;font color="#8080ff"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; p.first == s_; }&lt;br /&gt;
112 &lt;br /&gt;
113     string &lt;font color="#00ff00"&gt;const&lt;/font&gt;&amp; s_;&lt;br /&gt;
114 };&lt;br /&gt;
115 &lt;br /&gt;
116 &lt;font color="#00ff00"&gt;bool&lt;/font&gt; find_value( IniData &lt;font color="#00ff00"&gt;const&lt;/font&gt;&amp; ini, string &lt;font color="#00ff00"&gt;const&lt;/font&gt;&amp; s, string &lt;font color="#00ff00"&gt;const&lt;/font&gt;&amp; p, string &amp; res )&lt;br /&gt;
117 {&lt;br /&gt;
118     IniData::const_iterator sit = find_if(ini.begin(), ini.end(), first_is(s));&lt;br /&gt;
119     &lt;font color="#8080ff"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; (sit == ini.end())&lt;br /&gt;
120        &lt;font color="#8080ff"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; &lt;font color="#0000ff"&gt;false&lt;/font&gt;;&lt;br /&gt;
121 &lt;br /&gt;
122     Entries::const_iterator it = find_if(sit-&amp;gt;second.begin(), sit-&amp;gt;second.end(), first_is(p));&lt;br /&gt;
123     &lt;font color="#8080ff"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; (it == sit-&amp;gt;second.end())&lt;br /&gt;
124         &lt;font color="#8080ff"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; &lt;font color="#0000ff"&gt;false&lt;/font&gt;;&lt;br /&gt;
125 &lt;br /&gt;
126     res = it-&amp;gt;second;&lt;br /&gt;
127     &lt;font color="#8080ff"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; &lt;font color="#0000ff"&gt;true&lt;/font&gt;;&lt;br /&gt;
128 }&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
Вместо функтора first_is можно применить boost::bind, но я решил не мешать всё в одну кучу. С поиском всё просто: сначала в списке ищем секцию по имени, потом в списке записей секции ищем параметр по имени, и, если всё нашлось, то возвращаем значение параметра через параметр-ссылку.&lt;br /&gt;
&lt;br /&gt;
Осталось написать main.&lt;br /&gt;
&lt;code&gt; 130 &lt;font color="#00ff00"&gt;int&lt;/font&gt; main( &lt;font color="#00ff00"&gt;int&lt;/font&gt; argc, &lt;font color="#00ff00"&gt;char&lt;/font&gt;** argv)&lt;br /&gt;
131 {&lt;br /&gt;
132    &lt;font color="#8080ff"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; ( argc != &lt;font color="#0000ff"&gt;4&lt;/font&gt; )&lt;br /&gt;
133    {&lt;br /&gt;
134       cout &amp;lt;&amp;lt; &lt;font color="#0000ff"&gt;&amp;quot;Usage: &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; argv[] &amp;lt;&amp;lt; &lt;font color="#0000ff"&gt;&amp;quot; &amp;lt;file.ini&amp;gt; &amp;lt;section&amp;gt; &amp;lt;parameter&amp;gt;&amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; endl;&lt;br /&gt;
135       &lt;font color="#8080ff"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; ;&lt;br /&gt;
136    }&lt;br /&gt;
137 &lt;br /&gt;
138    ifstream in(argv[&lt;font color="#0000ff"&gt;1&lt;/font&gt;]);&lt;br /&gt;
139    &lt;font color="#8080ff"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt;( !in )&lt;br /&gt;
140    {&lt;br /&gt;
141       cout &amp;lt;&amp;lt; &lt;font color="#0000ff"&gt;&amp;quot;Can't open file &lt;/font&gt;&lt;font color="#0000ff"&gt;\&amp;quot;&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; argv[&lt;font color="#0000ff"&gt;1&lt;/font&gt;] &amp;lt;&amp;lt; &lt;font color="#0000ff"&gt;'\&amp;quot;'&lt;/font&gt; &amp;lt;&amp;lt; endl;&lt;br /&gt;
142       &lt;font color="#8080ff"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; &lt;font color="#0000ff"&gt;1&lt;/font&gt;;&lt;br /&gt;
143    }&lt;br /&gt;
144 &lt;br /&gt;
145    vector&amp;lt; string &amp;gt; lns;&lt;br /&gt;
146 &lt;br /&gt;
147    std::string s;&lt;br /&gt;
148    &lt;font color="#8080ff"&gt;&lt;b&gt;while&lt;/b&gt;&lt;/font&gt;( !in.eof() )&lt;br /&gt;
149    {&lt;br /&gt;
150       std::getline( in, s );&lt;br /&gt;
151       boost::algorithm::trim(s);&lt;br /&gt;
152       lns.push_back( s+=&lt;font color="#0000ff"&gt;'\n'&lt;/font&gt; );&lt;br /&gt;
153    }&lt;br /&gt;
154    lns.erase( remove_if(lns.begin(), lns.end(), is_comment()), lns.end());&lt;br /&gt;
155    string text = accumulate( lns.begin(), lns.end(), string() );&lt;br /&gt;
156 &lt;br /&gt;
157    IniData data;&lt;br /&gt;
158    inidata_parser parser(data); //  Our parser&lt;br /&gt;
159    BOOST_SPIRIT_DEBUG_NODE(parser);&lt;br /&gt;
160 &lt;br /&gt;
161    parse_info&amp;lt;&amp;gt; info = parse(text.c_str(), parser, nothing_p);&lt;br /&gt;
162    &lt;font color="#8080ff"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; (!info.hit)&lt;br /&gt;
163    {&lt;br /&gt;
164        cout &amp;lt;&amp;lt; &lt;font color="#0000ff"&gt;&amp;quot;Parse error&lt;/font&gt;&lt;font color="#0000ff"&gt;\n&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;quot;&lt;/font&gt;;&lt;br /&gt;
165        &lt;font color="#8080ff"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; &lt;font color="#0000ff"&gt;1&lt;/font&gt;;&lt;br /&gt;
166    }&lt;br /&gt;
167 &lt;br /&gt;
168    string res;&lt;br /&gt;
169    &lt;font color="#8080ff"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; (find_value(data, argv[&lt;font color="#0000ff"&gt;2&lt;/font&gt;], argv[&lt;font color="#0000ff"&gt;3&lt;/font&gt;], res))&lt;br /&gt;
170        cout &amp;lt;&amp;lt; res;&lt;br /&gt;
171    &lt;font color="#8080ff"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/font&gt;&lt;br /&gt;
172        cout &amp;lt;&amp;lt; &lt;font color="#0000ff"&gt;&amp;quot;Can't find requested parameter&amp;quot;&lt;/font&gt;;&lt;br /&gt;
173    cout &amp;lt;&amp;lt; endl;&lt;br /&gt;
174 }&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
Строки 132-136 — проверяем параметры программы: если их не 4, то выводим usage. Если с параметрами всё ок, то открываем файл (138-143). Если и с файлом всё нормально, то создаём массив строк lns (145) и считываем в него весь файл (147-153). После этого удаляем оттуда комментарии, используя припасённый функтор is_comment (154). В заключение склеиваем все строчки в одну (155).&lt;br /&gt;
&lt;br /&gt;
В строчках 157-159 создаётся и инициализируется парсер. Теперь запускаем парсер — для этого используется функция parse, которая принимает на вход сам текст, парсер и специальный парсер для пропускаемых символов (скажем, мы хотели бы пропускать все пробелы). В нашем случае парсер для пропускаемых символов будет пустым — nothing_p (т.е. ничего не парсящий). Результатом функции parse является структура parse_info&amp;lt;&amp;gt;. Нас интересует булево поле hit этой структуры, которое истинное, если не произошло ошибок. В строчках 162-166 мы сообщаем, если произошла ошибка. Осталось только найти параметр, заданный в командной строке и вывести его значение (168-173).&lt;br /&gt;
&lt;br /&gt;
Теперь код полностью написан. Компилируем его и запускаем на тестовом примере.&lt;br /&gt;
&lt;code&gt;$ g++ ini.cpp -o ini_cpp&lt;br /&gt;
&lt;br /&gt;
$ ./ini_cpp /usr/lib/firefox-3.0.5/application.ini App ID&lt;br /&gt;
{ec8030f7-c20a-464f-9b0e-13a3a9e97384}&lt;br /&gt;
&lt;br /&gt;
$ ./ini_cpp /usr/lib/firefox-3.0.5/application.ini App IDD&lt;br /&gt;
Can't find requested parameter&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
Надеюсь, что данная статья поможет вам написать свой собственный парсер =)&lt;br /&gt;
&lt;br /&gt;
&lt;hr width="80%"&gt;&lt;p&gt;P.S.: Наглым образом спёрто отсюда: &lt;a href="http://habrahabr.ru/blogs/cpp/50976/"&gt;Создаём парсер для ini-файлов на C++&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1252038906587337119-5996695384690498019?l=rakafon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rakafon.blogspot.com/feeds/5996695384690498019/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://rakafon.blogspot.com/2009/04/boostspirit.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/5996695384690498019'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/5996695384690498019'/><link rel='alternate' type='text/html' href='http://rakafon.blogspot.com/2009/04/boostspirit.html' title='Использование boost::spirit'/><author><name>Rakafon</name><uri>http://www.blogger.com/profile/03386514126069055282</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-wnns05XIxW4/Ti7XTMmujOI/AAAAAAAAABg/rZpn54sM7BI/s1600/20168127'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1252038906587337119.post-8918297723171743138</id><published>2009-04-01T22:10:00.001+03:00</published><updated>2010-10-15T14:00:27.264+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='boost'/><category scheme='http://www.blogger.com/atom/ns#' term='cpp'/><title type='text'>Использование boost::datetime</title><content type='html'>&lt;ul&gt;&lt;li&gt;Gregorian&lt;/li&gt;
&lt;li&gt;Posix Time&lt;/li&gt;
&lt;li&gt;Local Time&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Сейчас наверно сложно найти человека, который не столкнулся бы с необходимостью использования времени в своих целях, а точнее его цифрового представления. Цели могут быть совершенно разными, от простых замеров интервалов времени, в которые выполняется некий участок кода(совершенно не верный метод профайлинга, между прочим, но сейчас не об этом), до поддержки полноценных календарей в своих приложениях, которые должны быть актуальны для любого человека на земном шаре. Все эти манипуляции можно выполнить с помощью довольно аскетичной и простой в использовании, но в тоже время мощной библиотеки Boost.Date_Time. В библиотеке учитываются: високосный год, &lt;a href="http://ru.wikipedia.org/wiki/Високосная_секунда"&gt;високосная секунда&lt;/a&gt;, летнее время и т.д&lt;br /&gt;
Разберемся с некоторой терминологией, используемой в библиотеке:&lt;br /&gt;
В библиотеке существую три глобальных типа разделения времени:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;&lt;strong&gt;Time Point&lt;/strong&gt; — некая точка во временном континууме, например дата Вашего рождения &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Time Duration&lt;/strong&gt; — интервал времени, не привязанный ни к какой точке временного континуума&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Time Interval&lt;/strong&gt; — интервал времени, привязанный к некой точке во временном континууме&lt;/li&gt;
&lt;/ol&gt;&lt;br /&gt;
Так же необходимо помнить о разрешающей способности каждого метода получения времени, разрешающая способность(&lt;strong&gt;Resolution&lt;/strong&gt;) показывает — какая минимальная единица времени может быть использована при анализе имеющегося у вас объекта времени. Т.е это не что иное, как степень точности полученной временной точки. Наконец, перейдем к непосредственному знакомству с возможностями библиотеки.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/gregorian.html"&gt;boost::gregorian&lt;/a&gt;&lt;/h2&gt;&lt;br /&gt;
&lt;em&gt;Все примеры, используемые в данной статье подразумевает использование using namespace boost::&amp;lt;соответствующий_namespace&amp;gt; в начале каждого компилируемого юнита.&lt;/em&gt;&lt;br /&gt;
Данный компонент представляет нам &lt;a href="http://ru.wikipedia.org/wiki/Грегорианский_календарь"&gt;Грегорианский календарь &lt;/a&gt; и все мыслимые возможности работы с ним. Он в свою очередь делится на следующие компоненты:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/gregorian.html#date_time.gregorian.date_class"&gt;Date &lt;/a&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/gregorian.html#date_time.gregorian.date_duration"&gt;Date Duration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/gregorian.html#date_time.gregorian.date_period"&gt;Date Period&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/gregorian.html#date_time.gregorian.date_iterators"&gt;Date Iterators&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/gregorian.html#date_time.gregorian.date_algorithms"&gt;Date Generators/Algorithms&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Разберем назначение каждой из них:&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/gregorian.html#date_time.gregorian.date_class"&gt;&lt;strong&gt;boost::gregorian::date&lt;/strong&gt;&lt;/a&gt; — предназначен для простого хранения даты – точки во временном континууме. Поддерживает создание даты из строки определенного формата, а также посредством класса &lt;a href="http://www.boost.org/doc/libs/1_37_0/doc/html/boost/date_time/day_clock.html"&gt;boost::date_time::day_clock&lt;/a&gt;, основанного на стандартном механизме С\С++ связанным с &lt;a href="http://cplusplus.com/reference/clibrary/ctime/time_t/"&gt;time_t&lt;/a&gt;&lt;br /&gt;
Помимо хранения даты(которая не может быть изменена у объекта, кроме как посредством operator=) у класса есть методы* для получения конкретных частей даты(year(), month(), day() etc.), преобразования внутреннего представления даты в строку, определенного формата(to_simple_string(),to_iso_string(),to_iso_extended_string()) и конвертации в(и обратно) стандартную С\С++ структуру &lt;a href="http://cplusplus.com/reference/clibrary/ctime/tm/"&gt;tm&lt;/a&gt;(to_tm(),date_from_tm())&lt;br /&gt;
&lt;br /&gt;
*- &lt;em&gt;я не привожу описание каждой функции, более того я не буду, приводит полный список имеющихся функций, их список Вы можете посмотреть в ссылках, соответствующих конкретному классу. Функций довольно много и они довольно просты в использовании, так же я опускаю наличие параметров функции, если считаю это незначительным в данный момент.&lt;/em&gt;&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font color="black"&gt;date xGPWStart(1941, Jun, 22);&lt;br /&gt;
date xNowdays = day_clock::local_day();&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;The Great Patriotic War was started in &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; xGPWStart &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;And the current data is &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; xNowdays;&lt;/font&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;font color="gray"&gt;* This source code was highlighted with &lt;a href="http://virtser.net/blog/post/source-code-highlighter.aspx"&gt;&lt;font color="gray"&gt;Source Code Highlighter&lt;/font&gt;&lt;/a&gt;.&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;
&lt;br /&gt;
Вывод:&lt;br /&gt;
&lt;blockquote&gt;The Great Patriotic War was started in 1941-Jun-22&lt;br /&gt;
And the current data is 2009-Jul-26&lt;/blockquote&gt;&lt;br /&gt;
&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/gregorian.html#date_time.gregorian.date_duration"&gt;&lt;strong&gt;boost::gregorian::date_duration&lt;/strong&gt;&lt;/a&gt; — служит для подсчета дней, используя &lt;strong&gt;boost::gregorian::date&lt;/strong&gt; для вычислений.&lt;br /&gt;
Для удобства работы с &lt;b&gt;date_duration&lt;/b&gt; существуют три класса: &lt;strong&gt;months_duration&lt;/strong&gt;, &lt;strong&gt;years_duration&lt;/strong&gt; и &lt;strong&gt;weeks_duration&lt;/strong&gt;(так же есть typedef’ы на эти типы, представленные для удобства: &lt;strong&gt;months&lt;/strong&gt;, &lt;strong&gt;years&lt;/strong&gt; и &lt;strong&gt;weeks &lt;/strong&gt;соответственно), которые могут быть прибавлены или вычтены из date_duration чтобы получить желаемый результат. Существует подводный камень, связанный с этими тремя классами. Если использовать их в своих вычислениях, то Вы можете получить результат, который Вы не ожидаете. Приведу пример:&lt;br /&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font color="black"&gt;date xSomeDay(1999, Jan, 28);&lt;br /&gt;
date xDayInNextMonth;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;That's right: &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; ( xDayInNextMonth = xSomeDay + months(1) ) &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;And that's not: &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; xDayInNextMonth + months(1);&lt;br /&gt;
&lt;/font&gt;&lt;br /&gt;
&lt;font color="gray"&gt;* This source code was highlighted with &lt;a href="http://virtser.net/blog/post/source-code-highlighter.aspx"&gt;&lt;font color="gray"&gt;Source Code Highlighter&lt;/font&gt;&lt;/a&gt;.&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;
&lt;blockquote&gt;That's right: 1999-Feb-28&lt;br /&gt;
And that's not: 1999-Mar-31&lt;/blockquote&gt;&lt;br /&gt;
Такое поведение обусловлено особенностью класса &lt;strong&gt;months_duration&lt;/strong&gt;, который будет всегда использовать конец месяца в арифметических операциях, если изначальный объект указывал на одно из возможных чисел, которыми оканчиваются месяцы(28, 29, 30, 31). Будьте внимательны при использовании данного типа, кстати &lt;strong&gt;month_iterator&lt;/strong&gt; лишен этого недостатка(преимущества?), но о нем поговорим позже.&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/gregorian.html#date_time.gregorian.date_period"&gt;&lt;strong&gt;boost::gregorian::date_period&lt;/strong&gt;&lt;/a&gt; — класс представлен для удобного представления интервала между двумя датами, может быть использован для определения вхождения определенной даты во временной интервал(contains()), пересечения интервалов(intersects(), intersection()), смежности дат(is_adjacent()) и определения отношения расположения одной даты относительно другой(is_after(), is_before()). Кроме того, существуют методы для комбинации интервалов(merge(), span()) и их изменения(shift(), expand()). Важно помнить, что последний дегь в периоде не входит в весь период, т.е в периоде 1-Jan-1999\10-Jan-1999 последним днем будет 9 января, а не 10.&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font color="black"&gt;date_period xGPWDuration( date(1941, Jun, 22), date(1945, May, 9) );&lt;br /&gt;
date_period xStalinLifeYears( date(1878, Dec, 18), date(1953, Mar, 6) ); date_period xJukovsIncorrectLifeYears( date(1896, Dec, 6), date(1974, Jun, 14) );&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;The Great Patriotic War duration is &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; xGPWDuration &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;Was the GPW inside the Stalin's life years? &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; std::boolalpha &amp;lt;&amp;lt; xStalinLifeYears.contains(xGPWDuration) &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;Jukov's incorrect life years is &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; xJukovsIncorrectLifeYears &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
xJukovsIncorrectLifeYears.expand( days(5) );&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;Jukov's correct life years is &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; xJukovsIncorrectLifeYears &amp;lt;&amp;lt; std::endl; &lt;br /&gt;
&lt;font color="#008000"&gt;//Last day isn't included in the interval&lt;/font&gt;&lt;br /&gt;
date_period xFirstPeriod( date(1999, Jan, 1), date(1999, Jan, 10) );&lt;br /&gt;
date_period xSecondPeriod( date(1999, Jan, 10), date(1999, Jan, 12) );&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;Does these periods intersect? &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; std::boolalpha &amp;lt;&amp;lt; xFirstPeriod.intersects(xSecondPeriod) &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
&lt;/font&gt;&lt;br /&gt;
&lt;font color="gray"&gt;* This source code was highlighted with &lt;a href="http://virtser.net/blog/post/source-code-highlighter.aspx"&gt;&lt;font color="gray"&gt;Source Code Highlighter&lt;/font&gt;&lt;/a&gt;.&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;
Вывод:&lt;br /&gt;
&lt;blockquote&gt;The Great Patriotic War duration is [1941-Jun-22/1945-May-08]&lt;br /&gt;
Was the GPW inside the Stalin's life years? true&lt;br /&gt;
Jukov's incorrect life years is [1896-Dec-06/1974-Jun-13]&lt;br /&gt;
Jukov's correct life years is [1896-Dec-01/1974-Jun-18]&lt;br /&gt;
Does these periods intersect? false&lt;/blockquote&gt;&lt;br /&gt;
&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/gregorian.html#date_time.gregorian.date_iterators"&gt;&lt;strong&gt;boost::gregorian::date_iterator&lt;/strong&gt; &lt;/a&gt; — как должно быть понятно из названия – это типичный итератор, предназначенный для “движения” по датам. &lt;strong&gt;date_iterator&lt;/strong&gt; сам по себе не интересен, т.к является абстрактным классом, более интересны его классы-наследники: &lt;strong&gt;day_iterator&lt;/strong&gt;, &lt;strong&gt;week_iterator&lt;/strong&gt;, &lt;strong&gt;month_iterator&lt;/strong&gt;, &lt;strong&gt;year_iterator&lt;/strong&gt;. &lt;br /&gt;
В качестве примера используем пример из &lt;strong&gt;date_duration&lt;/strong&gt;, в котором мы получали некорректную дату (из-за подводных камней с месяцами). Как я и упоминал раньше, в &lt;b&gt;date_iterator&lt;/b&gt; подобных проблем нет:&lt;br /&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font color="black"&gt;month_iterator xSomeDay(date(1999, Jan, 28));&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;That's right: &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; *++xSomeDay &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;And that's too!: &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; *++xSomeDay;&lt;br /&gt;
&lt;/font&gt;&lt;br /&gt;
&lt;font color="gray"&gt;* This source code was highlighted with &lt;a href="http://virtser.net/blog/post/source-code-highlighter.aspx"&gt;&lt;font color="gray"&gt;Source Code Highlighter&lt;/font&gt;&lt;/a&gt;.&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;
&lt;blockquote&gt;That's right: 1999-Feb-28&lt;br /&gt;
And that's too!: 1999-Mar-28&lt;/blockquote&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/gregorian.html#date_time.gregorian.date_algorithms"&gt;&lt;strong&gt;Алгоритмы по работе с датами&lt;/strong&gt;&lt;/a&gt; — набор разнообразных классов и функций, для различных манипуляций над датами. Каждый класс имеет метод get_data() который позволяет получить дату, сгенерированную данным классом. Классы предоставляют нам следующий функционал:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Получить первый, последний или произвольный день для заданного месяца и недели(first_day_of_the_week_in_the_month(), last_day_of_the_week_in_the_month(), nth_day_of_the_week_in_the_month). День недели для поиска задается.&lt;/li&gt;
&lt;li&gt;Задать частичную дату(без указания года)(partial_date()). А потом получать полную дату, с помощью get_data()&lt;/li&gt;
&lt;li&gt;Вычислить первый день недели до или после заданной даты(first_day_of_the_week_before(), first_day_of_the_week_after()). День недели для вычисления задается&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Функции предоставляют следующий функционал:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Вычислить кол-во дней начиная от текущей даты, до следующего или предыдущего, заданного, дня недели(days_until_weekday(), days_before_week_day()).&lt;/li&gt;
&lt;li&gt;Сгенерировать дату, которая будет является датой следующего или предыдущего, заданного, дня недели. Новая дата будет сгенерирована, относительно предварительно заданной даты.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Примеры:&lt;br /&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font color="black"&gt;last_day_of_the_week_in_month xLastFriday(Friday, Jul);&lt;br /&gt;
partial_date xJunTen(10, Jun);&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;What is the date of the last friday in the July 2009? &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; xLastFriday.get_date(2009) &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;Just dusplay 10 Jun of 2009 &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; xJunTen.get_date(2009) &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;How much days from now till next friday? &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; days_until_weekday( day_clock::local_day(), greg_weekday(Friday) )&amp;lt;&amp;lt; std::endl;&lt;br /&gt;
&lt;/font&gt;&lt;br /&gt;
&lt;font color="gray"&gt;* This source code was highlighted with &lt;a href="http://virtser.net/blog/post/source-code-highlighter.aspx"&gt;&lt;font color="gray"&gt;Source Code Highlighter&lt;/font&gt;&lt;/a&gt;.&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;
Вывод:&lt;br /&gt;
&lt;blockquote&gt;What is the date of the last friday in the July 2009? 2009-Jul-31&lt;br /&gt;
Just dusplay 10 Jun of 2009 2009-Jun-10&lt;br /&gt;
How much days from now till next friday? 5&lt;/blockquote&gt;&lt;br /&gt;
&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/gregorian.html#date_time.gregorian.gregorian_calendar"&gt;&lt;strong&gt;boost::gregorian::gregorian_calendar&lt;/strong&gt;&lt;/a&gt; — предоставляет полезный набор статических функций для работы с датами.&lt;br /&gt;
Вместо описания функций, приведу пример их использования(функции просты и их название говорит само за себя):&lt;br /&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font color="black"&gt;  std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;What the day of the GPW begining? &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; DayToString( gregorian_calendar::day_of_week( gregorian_calendar::ymd_type(1941, Jun, 22) ) ) &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;And what is the number of this day frome the epoch start? &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; gregorian_calendar::day_number( gregorian_calendar::ymd_type(1941, Jun, 22) ) &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;And what is the number of this day frome the epoch start? &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; gregorian_calendar::day_number( gregorian_calendar::ymd_type(1400, Jan, 1) ) &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;What is the last day in the February 1941? &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; gregorian_calendar::end_of_month_day(1941, Feb) &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;What is the date of the 3333333 day from the epoch start? &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; date( gregorian_calendar::from_day_number(3333333) ) &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;Is the 2004 year a leap year? &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; std::boolalpha &amp;lt;&amp;lt; gregorian_calendar::is_leap_year(2004) &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
&lt;/font&gt;&lt;br /&gt;
&lt;font color="gray"&gt;* This source code was highlighted with &lt;a href="http://virtser.net/blog/post/source-code-highlighter.aspx"&gt;&lt;font color="gray"&gt;Source Code Highlighter&lt;/font&gt;&lt;/a&gt;.&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;
Вывод:&lt;br /&gt;
&lt;blockquote&gt;What the day of the GPW begining? Sunday&lt;br /&gt;
And what is the number of this day frome the epoch start? 2430168&lt;br /&gt;
And what is the number of this day frome the epoch start? 2232400&lt;br /&gt;
What is the last day in the February 1941? 28&lt;br /&gt;
What is the date of the 3333333 day from the epoch start? 4414-Apr-03&lt;br /&gt;
Is the 2004 year a leap year? true&lt;/blockquote&gt;&lt;br /&gt;
Эмпирическим путем было получено, что для функций day_number() и from_day_number() минимальными значениями являются 1400-Jan-1 и 2232400 соответственно. Если пытаться использовать дату ранее 1400-Jan-1, то получим исключение. То же справедливо и для количества дней.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/posix_time.html"&gt;boost::posix_time&lt;/a&gt;&lt;/h2&gt;&lt;br /&gt;
Данный компонент предоставляет нам удобный метод работы с точками во времени, но в отличие от &lt;strong&gt;boost::gregorian boost::posix_time&lt;/strong&gt; предоставляет возможность работы с временными точками более низкого разрешения (вплоть до наносекунд), высокая часть разрешения(дата) реализуется с помощью &lt;strong&gt;boost::gregorian&lt;/strong&gt;. Компонент особенно удобен для задач, в которых необходима высокая точность получения времени(например строка записи в лог файле). Он делится на следующие части:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/posix_time.html#date_time.posix_time.ptime_class"&gt;Ptime&lt;/a&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/posix_time.html#date_time.posix_time.time_duration"&gt;Time Duration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/gregorian.html#date_time.gregorian.date_period"&gt;Date Period&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/posix_time.html#date_time.posix_time.time_period"&gt;Time Period&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/posix_time.html#date_time.posix_time.time_iterators"&gt;Time Iterators&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Разберем назначение каждой части:&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/posix_time.html#date_time.posix_time.ptime_class"&gt;&lt;strong&gt;boost::posix_time::ptime&lt;/strong&gt;&lt;/a&gt; — представляет собой точку во временном континууме. Очень похожа на &lt;strong&gt;boost::gregorian:date&lt;/strong&gt; но с разрешением до микросекунд. При создании экземпляра класса только по &lt;b&gt;gregorian:date&lt;/b&gt;, “низкоразрешающая” часть устанавливается в полночь(все нули).&lt;br /&gt;
Пример использования:&lt;br /&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font color="black"&gt;ptime xTime(date(1961, Apr, 12), hours(9) + minutes(7));&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;Did you know that Gagrin said \&amp;quot;Poehali\&amp;quot; at &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; xTime &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;\n&amp;quot;&lt;/font&gt;;&lt;br /&gt;
ptime xTimeStr( time_from_string(&lt;font color="#A31515"&gt;&amp;quot;1961-04-12 09.07.00.0000&amp;quot;&lt;/font&gt;) );&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;And the same time point constructed from a string: &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; xTimeStr &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;\n&amp;quot;&lt;/font&gt;;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;Current time with second resolution: &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; second_clock::local_time() &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;\nAnd with microsecond:&amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; microsec_clock::local_time();&lt;br /&gt;
&lt;/font&gt;&lt;br /&gt;
&lt;font color="gray"&gt;* This source code was highlighted with &lt;a href="http://virtser.net/blog/post/source-code-highlighter.aspx"&gt;&lt;font color="gray"&gt;Source Code Highlighter&lt;/font&gt;&lt;/a&gt;.&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;
Вывод:&lt;br /&gt;
&lt;blockquote&gt;Did you know that Gagrin said «Poehali» at 1961-Apr-12 09:07:00&lt;br /&gt;
And the same time point constructed from a string: 1961-Apr-12 09:07:00&lt;br /&gt;
Current time with second resolution: 2009-Jul-29 16:41:51&lt;br /&gt;
And with microsecond:2009-Jul-29 16:41:51.087000&lt;/blockquote&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/posix_time.html#date_time.posix_time.time_duration"&gt;&lt;strong&gt;boost::posix_time::time_duration&lt;/strong&gt;&lt;/a&gt; — представляет собой длительность во времени, которая не привязана к конкретной дате. Максимальное разрешение длительности ограничено наносекундами, если библиотека собрана с макросом &lt;strong&gt;BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG&lt;/strong&gt;, и микросекундами, по умолчанию. Из объекта может быть получена информация о количестве секунд\микросекунд\миллисекунд\наносекунд(при соответствующей сборке) которые содержатся в текущей временной длительности.&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font color="black"&gt;time_duration xTime(1,2,3);&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;Print time: &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; xTime &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;\n&amp;quot;&lt;/font&gt;;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;Print increased time: &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; xTime + hours(3) + seconds(2) + minutes(6) + milliseconds(15) + microseconds(25) &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;\n&amp;quot;&lt;/font&gt;;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;Print total seconds: &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; xTime.total_seconds() &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot; milliseconds: &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; &lt;br /&gt;
xTime.total_milliseconds() &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot; microseconds: &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; xTime.total_microseconds() &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;\n&amp;quot;&lt;/font&gt;;&lt;br /&gt;
&lt;/font&gt;&lt;br /&gt;
&lt;font color="gray"&gt;* This source code was highlighted with &lt;a href="http://virtser.net/blog/post/source-code-highlighter.aspx"&gt;&lt;font color="gray"&gt;Source Code Highlighter&lt;/font&gt;&lt;/a&gt;.&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;
Вывод:&lt;br /&gt;
&lt;blockquote&gt;Print time: 01:02:03&lt;br /&gt;
Print increased time: 04:08:05.015025&lt;br /&gt;
Print total seconds: 3723 milliseconds: 3723000 microseconds: 3723000000&lt;/blockquote&gt;&lt;br /&gt;
&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/posix_time.html#date_time.posix_time.time_period"&gt;&lt;strong&gt;boost::posix_time::time_period&lt;/strong&gt;&lt;/a&gt; — представляет собой отрезок во времени, класс схож &lt;strong&gt;gregorian::date_period&lt;/strong&gt;, но имеет более низкую разрешающую способность. Функционал класса позволяет определять вхождение(contains()), пересечение(intersects()) и длину(length()) интервалов. Так же существует возможность расширения(expand()), смещения(shift()) и объединения(merge()) интервалов. &lt;br /&gt;
Пример:&lt;br /&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font color="black"&gt;  ptime xDoomsday( date(2012, Jan, 1) );&lt;br /&gt;
time_period xArmageddonLast(xDoomsday, hours(1));&lt;br /&gt;
time_period xChakNorrisSmoke(xDoomsday, minutes(1));&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;Doomsday was during: &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; xArmageddonLast&amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;\n&amp;quot;&lt;/font&gt;;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;Chak Norris was smoking at &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; xChakNorrisSmoke &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;\n&amp;quot;&lt;/font&gt;;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;Did Chak Norris smoke during Doomsday breathtaking?&amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; std::boolalpha &amp;lt;&amp;lt;xArmageddonLast.contains(xChakNorrisSmoke);&lt;/font&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;font color="gray"&gt;* This source code was highlighted with &lt;a href="http://virtser.net/blog/post/source-code-highlighter.aspx"&gt;&lt;font color="gray"&gt;Source Code Highlighter&lt;/font&gt;&lt;/a&gt;.&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;
Вывод:&lt;br /&gt;
&lt;blockquote&gt;Doomsday was during: [2012-Jan-01 00:00:00/2012-Jan-01 00:59:59.999999]&lt;br /&gt;
Chak Norris was smoking at [2012-Jan-01 00:00:00/2012-Jan-01 00:00:59.999999]&lt;br /&gt;
Did Chak Norris smoke during Doomsday breathtaking?true&lt;/blockquote&gt;&lt;br /&gt;
&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/posix_time.html#date_time.posix_time.time_iterators"&gt;&lt;strong&gt;boost::posix_time::time_iterator&lt;/strong&gt;&lt;/a&gt; — предназначен(как наверное все догадались :) ) для итерации по времени. Приятной особенностью данного итератора является возможность задания временного интервала, который будет использоваться при итерации, т.е. насколько и в каких единицах будет изменяться текущая точка во временном континууме при каждой итерации. В качестве временных единиц могут быть использованы все единицы от часа до наносекунд (если собрано с соответствующим флагом)&lt;br /&gt;
Приведу маленький пример:&lt;br /&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font color="black"&gt;ptime xTime(date(2012, Jan, 1));&lt;br /&gt;
time_iterator xIt(xTime, hours(6));&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;6 hours after Domsday has come!!!&amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; *++xIt;&lt;br /&gt;
&lt;/font&gt;&lt;br /&gt;
&lt;font color="gray"&gt;* This source code was highlighted with &lt;a href="http://virtser.net/blog/post/source-code-highlighter.aspx"&gt;&lt;font color="gray"&gt;Source Code Highlighter&lt;/font&gt;&lt;/a&gt;.&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;
Вывод:&lt;br /&gt;
&lt;blockquote&gt;6 hours after Domsday has come!!!2012-Jan-01 06:00:00&lt;/blockquote&gt;&lt;br /&gt;
&lt;h2&gt;&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/local_time.html"&gt;Local Time System&lt;/a&gt;&lt;/h2&gt;&lt;br /&gt;
Данный компонент предоставляет нам возможность работы со временем, в разных часовых поясах и с разными правилами перехода на летнее время. Это достаточно мощный и нужный компонент, особенно необходимый для тех приложений где важно не просто текущее(локальное) время, а важен учет различных смещений во времени, согласно региональным соглашениям относительно времени(переход на летние время, часовой пояс и т.д). Итак, приведу список частей, которые входят в данный компонент:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/local_time.html#date_time.local_time.posix_time_zone"&gt;Posix Time Zone&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/local_time.html#date_time.local_time.tz_database"&gt;Time Zone Database&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/local_time.html#date_time.local_time.custom_time_zone"&gt;Custom Time Zone&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/local_time.html#date_time.local_time.local_date_time"&gt;Local Date Time&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/local_time.html#date_time.local_time.local_time_period"&gt;Local Time Period&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/local_time.html#date_time.local_time.posix_time_zone"&gt;&lt;strong&gt;boost::local_time:: posix_time_zone&lt;/strong&gt;&lt;/a&gt; представляет собой набор данных и правил для представления часовых поясов(смещение относительно GMT, правила перехода на летнее время и обратно, название часового пояса и его аббревиатура). Объект данного типа создается на основании строки, формат строки является стандартизированным POSIX форматом(IEEE Std 1003.1) для часовых поясов.&lt;br /&gt;
В общем виде эта строка выглядит следующим образом:&lt;br /&gt;
&lt;em&gt;std offset dst [offset],start[/time],end[/time]&lt;/em&gt;&lt;br /&gt;
&lt;strong&gt;std&lt;/strong&gt; — Аббревиатура часового пояса.&lt;br /&gt;
&lt;strong&gt;offset &lt;/strong&gt; — Смещение относительно GMT.&lt;br /&gt;
&lt;strong&gt;dst &lt;/strong&gt; — Аббревиатура часового пояса, во время действия летнего времени.&lt;br /&gt;
&lt;strong&gt;[offset] &lt;/strong&gt; — Показывает насколько изменяется время (в часах), при переходе на летнее время. Опциональный параметр.&lt;br /&gt;
&lt;strong&gt;start и end &lt;/strong&gt; — Задают интервал действия летнего времени.&lt;br /&gt;
&lt;strong&gt;[/time] &lt;/strong&gt; — Задает точное время в пределах дня, в которое начинается переход на летнее время или летнее время прекращает свое действие.&lt;br /&gt;
&lt;strong&gt;offset&lt;/strong&gt; и &lt;strong&gt;time&lt;/strong&gt; имеют следующий формат: [+|-]hh[:mm[:ss]] {h=0-23, m/s=0-59}&lt;br /&gt;
&lt;strong&gt;start&lt;/strong&gt; и &lt;strong&gt;end &lt;/strong&gt; могут быть представлены в одном из следующих форматов:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Mm.w.d {month=1-12, week=1-5 (5 всегда последняя), day=0-6}&lt;/li&gt;
&lt;li&gt;Jn {n=1-365 29 февраля – не учитывается} &lt;/li&gt;
&lt;li&gt;n {n=0-365 Учитывает 29 февраля в високосные годы}&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Каждую часть этой строки вы может получить отдельно, с помощью методов данного класса. Не вижу смысла приводить здесь их имена, они достаточно прозрачны и отражают суть их назначения, так что обратитесь к документации, за их списком. &lt;br /&gt;
В качестве примера я использовал часовой пояс GMT+3(Московское время):&lt;br /&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font color="black"&gt;posix_time_zone xZone(&lt;font color="#A31515"&gt;&amp;quot;MSK+3MSD+01,M3.5.0/02:00,M10.5.0/02:00&amp;quot;&lt;/font&gt;);&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;Dailight period in 2009 started at &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; xZone.dst_local_start_time(2009) &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;\nAnd it will finish at &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; xZone.dst_local_end_time(2009);&lt;/font&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;font color="gray"&gt;* This source code was highlighted with &lt;a href="http://virtser.net/blog/post/source-code-highlighter.aspx"&gt;&lt;font color="gray"&gt;Source Code Highlighter&lt;/font&gt;&lt;/a&gt;.&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;
&lt;br /&gt;
Вывод:&lt;br /&gt;
&lt;blockquote&gt;Dailight period in 2009 started at 2009-Mar-29 02:00:00&lt;br /&gt;
And it will finish at 2009-Oct-25 02:00:00 &lt;/blockquote&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/local_time.html#date_time.local_time.tz_database"&gt;&lt;strong&gt;boost::local_time::tz_database&lt;/strong&gt;&lt;/a&gt; — удобный класс для хранения множества различных часовых поясов. При создании объекта, создается пустая база данных (громко сказано конечно :) ), после чего она может быть вручную заполнена, с помощью метода add_record() или же прочитана из csv(comma separated values) файла, пример такого файла(с большим количеством записей) содержится в &lt;em&gt;%boost%\libs\date_time\data\date_time_zonespec.csv&lt;/em&gt;&lt;br /&gt;
Формат записи внутри этого файла, должен удовлетворять следующему стандарту: &lt;blockquote&gt;«ID»,«STD ABBR»,«STD NAME»,«DST ABBR»,«DST NAME»,«GMT offset»,«DST adjustment»,«DST Start Date rule»,«Start time»,«DST End date rule»,«End time»&lt;/blockquote&gt;&lt;br /&gt;
Где:&lt;br /&gt;
&lt;strong&gt;ID&lt;/strong&gt; – Содержит строку, однозначно идентифицирующую данный часовой пояс.&lt;br /&gt;
&lt;strong&gt;STD ABBR, STD NAME, DST ABBR, DST NAME&lt;/strong&gt; — Эти поля заполняются строками с именами и аббревиатурами стандартного и летнего времен, зачастую имена и аббревиатуры идентичны. &lt;br /&gt;
&lt;strong&gt;GMT offset&lt;/strong&gt; — Смещение во времени, относительно Гринвича. Его формат: &lt;em&gt;{+|-}hh:mm[:ss]&lt;/em&gt;&lt;br /&gt;
&lt;strong&gt;DST adjustment &lt;/strong&gt; — Смещение относительно &lt;strong&gt;GMT offset&lt;/strong&gt; во время действия “летнего времени”. Формат тот же, что и у &lt;strong&gt;GMT offset&lt;/strong&gt;.&lt;br /&gt;
&lt;strong&gt;DST Start Date rule&lt;/strong&gt; — Строка описывающая день в году, который возвещает начало периода “летнего времени”. Так же имеет свой формат(сколько можно форматов разных?): &lt;blockquote&gt;&lt;strong&gt;weekday;day-of-week;month&lt;/strong&gt;&lt;br /&gt;
Где:&lt;br /&gt;
&lt;strong&gt;weekday&lt;/strong&gt; — Порядковое числительное, индицирующее какой по счету день в месяце, нас интересует.&lt;br /&gt;
&lt;strong&gt;day-of-week &lt;/strong&gt; — день недели.&lt;br /&gt;
&lt;strong&gt;month &lt;/strong&gt; — месяц.&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;blockquote&gt;&lt;strong&gt;-1;0;3&lt;/strong&gt; – Начало “летнего времени” в России(последнее воскресенье марта)&lt;/blockquote&gt;&lt;/blockquote&gt;&lt;br /&gt;
&lt;strong&gt;Start time&lt;/strong&gt; — Время после полуночи, в которое вступает в силу “летнее время”. Формат тот же, что и у &lt;strong&gt;GMT offset&lt;/strong&gt;.&lt;br /&gt;
&lt;strong&gt;DST End date rule&lt;/strong&gt; — Строка описывающая день в году, который возвещает конец периода “летнего времени”. Формат идентичен &lt;strong&gt;DST Start Date rule&lt;/strong&gt;.&lt;br /&gt;
&lt;strong&gt;End time&lt;/strong&gt; — Аналог &lt;strong&gt;Start time&lt;/strong&gt;, только для окончания “летнего времени”.&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font color="black"&gt;tz_database xDb;&lt;br /&gt;
xDb.load_from_file(&lt;font color="#A31515"&gt;&amp;quot;G:\\Program files\\boost\\boost_1_39_0\\\libs\\date_time\\data\\date_time_zonespec.csv&amp;quot;&lt;/font&gt;);&lt;br /&gt;
&lt;font color="#0000ff"&gt;const&lt;/font&gt; std::vector&amp;lt;std::&lt;font color="#0000ff"&gt;string&lt;/font&gt;&amp;gt;&amp; xAllRegions = xDb.region_list();&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;Print first 10 zone IDs from the boost time zone file:&amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
&lt;font color="#0000ff"&gt;for&lt;/font&gt;(std::vector&amp;lt;std::&lt;font color="#0000ff"&gt;string&lt;/font&gt;&amp;gt;::const_iterator it = xAllRegions.begin(); it != xAllRegions.begin() + 10; ++it)&lt;br /&gt;
std::cout &amp;lt;&amp;lt; *it &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;And time when daylight saving was started at 2009: &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; xDb.time_zone_from_region(&lt;font color="#A31515"&gt;&amp;quot;Europe/Moscow&amp;quot;&lt;/font&gt;)-&amp;gt;dst_local_start_time(2009) &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
&lt;/font&gt;&lt;br /&gt;
&lt;font color="gray"&gt;* This source code was highlighted with &lt;a href="http://virtser.net/blog/post/source-code-highlighter.aspx"&gt;&lt;font color="gray"&gt;Source Code Highlighter&lt;/font&gt;&lt;/a&gt;.&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;
&lt;br /&gt;
Вывод:&lt;br /&gt;
&lt;blockquote&gt;Print first 10 zone IDs from the boost time zone file:&lt;br /&gt;
Africa/Abidjan&lt;br /&gt;
Africa/Accra&lt;br /&gt;
Africa/Addis_Ababa&lt;br /&gt;
Africa/Algiers&lt;br /&gt;
Africa/Asmera&lt;br /&gt;
Africa/Bamako&lt;br /&gt;
Africa/Bangui&lt;br /&gt;
Africa/Banjul&lt;br /&gt;
Africa/Bissau&lt;br /&gt;
Africa/Blantyre&lt;br /&gt;
And time when daylight saving was started at 2009: 2009-Mar-29 02:00:00&lt;/blockquote&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/local_time.html#date_time.local_time.custom_time_zone"&gt;&lt;strong&gt;boost::local_time::custom_time_zone&lt;/strong&gt;&lt;/a&gt; — класс для создания описания часового пояса, но в отличие от прежде описанного &lt;strong&gt;boost::local_time::posix_time_zone &lt;/strong&gt;, данный класс использует четыре других класса, при конструировании часового пояса. Это классы: &lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/posix_time.html#date_time.posix_time.time_duration"&gt;time_duration &lt;/a&gt;, &lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/local_time.html#time_zone_names"&gt;time_zone_names &lt;/a&gt;, &lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/local_time.html#dst_adjustment_offsets"&gt;dst_adjustment_offsets&lt;/a&gt; и &lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/local_time.html#date_time.local_time.dst_calc_rules"&gt;dst_calc_rule&lt;/a&gt;. Так как класс не выделяется ничем выдающимся, то просто приведу пример его использования:&lt;br /&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font color="black"&gt;time_zone_names xNames(&lt;font color="#A31515"&gt;&amp;quot;Moscow Standart Time&amp;quot;&lt;/font&gt;, &lt;font color="#A31515"&gt;&amp;quot;MST&amp;quot;&lt;/font&gt;, &lt;font color="#A31515"&gt;&amp;quot;Moscow Daylight Time&amp;quot;&lt;/font&gt;, &lt;font color="#A31515"&gt;&amp;quot;MDT&amp;quot;&lt;/font&gt;);&lt;br /&gt;
time_duration xGMTOffset(3, 0, 0);&lt;br /&gt;
dst_adjustment_offsets xRulesOffsets( time_duration(1,0,0), time_duration(2,0,0), time_duration(3,0,0) );&lt;br /&gt;
&lt;font color="#008000"&gt;//Mak daylight's rule&lt;/font&gt;&lt;br /&gt;
last_day_of_the_week_in_month xStartRule(Sunday, Mar);&lt;br /&gt;
last_day_of_the_week_in_month xEndRule(Sunday, Oct);&lt;br /&gt;
&lt;br /&gt;
boost::shared_ptr&amp;lt;dst_calc_rule&amp;gt; xRules( &lt;font color="#0000ff"&gt;new&lt;/font&gt; last_last_dst_rule(xStartRule, xEndRule) );&lt;br /&gt;
custom_time_zone xCustomTimeZone(xNames, xGMTOffset, xRulesOffsets, xRules);&lt;br /&gt;
&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;The our time zone name is: &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; xCustomTimeZone.std_zone_name() &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;\n&amp;quot;&lt;/font&gt;&lt;br /&gt;
&amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;It has an &amp;quot;&lt;/font&gt;&amp;lt;&amp;lt; xCustomTimeZone.base_utc_offset() &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot; offset from GMT.\n&amp;quot;&lt;/font&gt;&lt;br /&gt;
&amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;And daylight period will end at &amp;quot;&lt;/font&gt;&amp;lt;&amp;lt; xCustomTimeZone.dst_local_end_time(2009) &amp;lt;&amp;lt;std::endl;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;Posix string which represents our custom_time_zone object is:\n&amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; xCustomTimeZone.to_posix_string();&lt;br /&gt;
&lt;/font&gt;&lt;br /&gt;
&lt;font color="gray"&gt;* This source code was highlighted with &lt;a href="http://virtser.net/blog/post/source-code-highlighter.aspx"&gt;&lt;font color="gray"&gt;Source Code Highlighter&lt;/font&gt;&lt;/a&gt;.&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;
Вывод:&lt;br /&gt;
&lt;blockquote&gt;The our time zone name is: Moscow Standart Time&lt;br /&gt;
It has an 03:00:00 offset from GMT.&lt;br /&gt;
And daylight period will end at 2009-Oct-25 03:00:00&lt;br /&gt;
Posix string which represents our custom_time_zone object is:&lt;br /&gt;
MST+03MDT+01,M3.5.0/02:00,M10.5.0/03:00&lt;/blockquote&gt;&lt;br /&gt;
Классы &lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/local_time.html#date_time.local_time.local_date_time"&gt;&lt;strong&gt;boost::local_time::local_date_time&lt;/strong&gt;&lt;/a&gt; и &lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/local_time.html#date_time.local_time.local_time_period"&gt;&lt;strong&gt;boost::local_time::local_time_period&lt;/strong&gt;&lt;/a&gt; повторяют схожие классы из &lt;strong&gt;boost::posix_time&lt;/strong&gt;, с привязкой к часовому поясу, поэтому я не буду их рассматривать.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;Полезные особенности и заключение&lt;/h2&gt;&lt;br /&gt;
В Boost.Data_time, помимо классов для создания дат, есть полезные утилиты, такие как: &lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/date_time_io.html"&gt;форматируемая обработка ввода\вывода&lt;/a&gt; и &lt;a href="http://www.boost.org/doc/libs/1_39_0/doc/html/date_time/serialization.html"&gt;сериализация&lt;/a&gt;. Оба механизма достаточно просты. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
P.S.: Наглым образом спёрто отсюда: &lt;a href="http://habrahabr.ru/blogs/cpp/66318/"&gt;Boost это просто. Часть 2. Boost.Date_time&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1252038906587337119-8918297723171743138?l=rakafon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rakafon.blogspot.com/feeds/8918297723171743138/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://rakafon.blogspot.com/2009/04/boostdatetime.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/8918297723171743138'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/8918297723171743138'/><link rel='alternate' type='text/html' href='http://rakafon.blogspot.com/2009/04/boostdatetime.html' title='Использование boost::datetime'/><author><name>Rakafon</name><uri>http://www.blogger.com/profile/03386514126069055282</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-wnns05XIxW4/Ti7XTMmujOI/AAAAAAAAABg/rZpn54sM7BI/s1600/20168127'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1252038906587337119.post-2229152132418543560</id><published>2009-04-01T22:00:00.001+03:00</published><updated>2010-10-15T14:00:33.856+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='boost'/><category scheme='http://www.blogger.com/atom/ns#' term='cpp'/><title type='text'>Использование интеллектуальных указателей из boost</title><content type='html'>&lt;p&gt;Ни для кого не секрет, что работа с динамической памятью и системными ресурсами вообще является одним из самых сложных аспектов при программировании на С++. Сложность этой проблемы заключается в том, что память и ресурсы имеют обыкновение утекать… Безвозвратно и бесконтрольно. И если синтаксические и логические ошибки выловить в программе достаточно просто, то на поиск утечек памяти уходит не одна неделя. За все время существования этой проблемы разработчиками было придумано множество путей облегчения себе жизни. Кто-то, избрав путь наименьшего сопротивления, перешел на такие языки, как Java или C#, где за ресурсами следить вроде как не надо – на это существуют сборщики мусора, а динамическая память (в понимании С++) отсутствует как класс. Кто-то вооружившись BoundsChecker’ом анализирует результаты работы программы с целью выявить места, в которых происходит утечка. Кто-то, набравшись терпения, пишет собственные менеджеры памяти и сборщики мусора для С++. А кто-то, взяв на вооружения некоторые идеи языка С++, разрабатывает т. н. ведущие указатели, дабы, оставаясь в рамках языка, исключить саму возможность утечек.&lt;/p&gt;&lt;!--StartFragment--&gt;   &lt;p&gt;Что есть ведущий указатель (или, иначе говоря Smart Pointer)? Это объект, поведение которого не отличается (ну, или почти не отличается) от поведения обычного указателя, но обладающий при этом рядом достоинств, отсутствующих у обычного указателя. Вообще говоря, по этому поводу написано столько, что писать еще раз тоже самое – большого смыла нет. Достаточно лишь упомянуть вот о чем. Ведущие (или умные) указатели обычно подразделяются на два основных типа – «слабые» и с «подсчетом ссылок». Слабые указатели позволяют без лишних затрат освободить хранящийся в них объект по выходу из блока, в котором такой указатель был объявлен. Тем самым решается проблема «потерянных ссылок», когда разработчик, по невнимательности, забывает освобождать динамическую память, указатель на которую сохраняется на стеке:&lt;/p&gt;&lt;pre&gt;void SomeFunc()
{
char* buff = new char[16];
_itoa(125, buff, 10);

}
&lt;/pre&gt;&lt;p&gt;В этом примере буфер был выделен, но не был удален. Указатели же с подсчетом ссылок позволяют контролировать объект в течение гораздо более длительного срока. Достигается это тем, что такой указатель «считает ссылки» на указываемый объект и удаляет только тогда, когда контролируемый объект уже никому не нужен. Пример: Объявляется класс:&lt;/p&gt;&lt;pre&gt;class SomeClass
{
public:
   SomeClass() {m_SomeObject = new int;}

   ~SomeClass() {delete m_SomeObject;}
private:
   int *m_SomeObject;
};
// потом где-то в коде имеет место такая конструкция:

SomeClass obj1;
{
   SomeClass obj2(obj1);
   // Что-то делаем с объектом obj1
}
// Что-то делаем с объектом obj2
&lt;/pre&gt;&lt;p&gt;Что произойдет? Правильно. После выхода из блока и вызова деструктора для obj2 указатель в obj1 станет недействительным. Избежать этого можно переписав конструктор копий и оператор присваивания. Но есть и более простой путь – воспользоваться указателем с подсчетом ссылок. Такой указатель можно реализовать самому. И наверняка многие так и делают. Но это не что иное, как изобретение велосипеда, название которому – boost::smart_ptr.&lt;/p&gt;&lt;h2&gt;Как это использовать&lt;/h2&gt;&lt;h3&gt;scoped_ptr, shared_ptr, scoped_array, shared_array&lt;/h3&gt;&lt;div&gt;    &lt;p&gt;Этот раздел библиотеки включает в себя группу классов, реализующих обе вышеописанные разновидности указателей: &lt;strong&gt;boost::scoped_ptr&lt;/strong&gt; и &lt;strong&gt;boost::shared_ptr&lt;/strong&gt; Первый используется для контроля времени жизни указателя в пределах операторного блока. Второй – для длительного контроля за указателем. Существуют разновидности этих классов для указателей на массивы: &lt;strong&gt;boost::scoped_array&lt;/strong&gt; и &lt;strong&gt;boost::shared_array&lt;/strong&gt; соответственно. Разница между этими группами классов очевидна. Первые для удаления контролируемого указателя используют оператор delete, а вторые – оператор delete[]. По этому путать их не рекомендуется во избежании возможных неприятностей с менеджером памяти. В общем случае использовать экземпляры этих классов можно почти также, как и указатели:&lt;/p&gt;&lt;pre&gt;boost::shared_ptr&amp;lt;SomeClass&amp;gt; ptr(new SomeClass);
ptr-&amp;gt;SomeFunc(); // вызываем метод класса по указателю

std::cout &amp;lt;&amp;lt; *ptr; // выводим экземпляр класса в поток.
// а вот и то самое «почти»:
SomeClass* ptr1;
if (ptr == ptr1) // тут будет ошибка компиляции

   // что-то делаем
&lt;/pre&gt;&lt;p&gt;Дело в том, что ведущим указателям не рекомендуется иметь оператора преобразования к указываемому типу (подробней об этом можно прочитать у Александреску). Для получения явного указателя на ведущий объект используется метод get. Кроме метода &lt;strong&gt;get&lt;/strong&gt; для этих классов определены следующие методы:&lt;/p&gt;&lt;table border="1"&gt;&lt;tr&gt;         &lt;th align="left"&gt;Метод&lt;/th&gt;         &lt;th align="left"&gt;Назначение&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;         &lt;td colspan="2"&gt;&lt;strong&gt;Общие&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;         &lt;th align="left"&gt;reset&lt;/th&gt;         &lt;td&gt;Уменьшает счетчик ссылок на единицу (если для shared_ptr) и, если необходимо, удаляет объект&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;         &lt;th align="left"&gt;swap&lt;/th&gt;         &lt;td&gt;Обменивает значения двух объектов&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;         &lt;td colspan="2"&gt;&lt;strong&gt;scoped_array/shared_array&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;         &lt;th align="left"&gt;operator []&lt;/th&gt;         &lt;td&gt;Предоставляет доступ по индексу&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;         &lt;td colspan="2"&gt;&lt;strong&gt;shared_ptr/shared_array&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;         &lt;th align="left"&gt;unique&lt;/th&gt;         &lt;td&gt;Возвращает true, если счетчик ссылок == 1&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;         &lt;th align="left"&gt;use_count&lt;/th&gt;         &lt;td&gt;Возвращает значения счетчика ссылок&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;         &lt;th align="left"&gt;operator bool&lt;/th&gt;         &lt;td&gt;Возвращает true, если указатель проинициализирован&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;p&gt;Подробно о сигнатурах этих методов можно прочитать в документации. Приведенные выше примеры кода с использованием этих классов будут выглядеть так:&lt;/p&gt;&lt;pre&gt;void SomeFunc()

{
scoped_array&amp;lt;char&amp;gt; buff = new char[16];
_itoa(125, buff.get(), 10);

}

class SomeClass
{
public:
   SomeClass() {m_SomeObject.reset(new int);}

private:
   boost::shared_ptr&amp;lt;int&amp;gt; m_SomeObject;
};
&lt;/pre&gt;&lt;p&gt;Применение этих классов достаточно прозрачно, и не должно представлять каких-либо затруднений. Кроме этих четырех классов в джентельменский набор умных указателей входят еще два класса-помошника: &lt;strong&gt;boost::weak_ptr&lt;/strong&gt; и &lt;strong&gt;boost::intrusive_ptr&lt;/strong&gt;&lt;/p&gt;&lt;h3&gt;weak_ptr&lt;/h3&gt;&lt;div&gt;    &lt;p&gt;Первый (boost::weak_ptr) используется в паре с shared_ptr для хранения ссылок на объекты типа boost::shared_ptr. Так же, как и обычные ссылки/указатели на shared_ptr, weak_ptr не увеличивает счетчик ссылок. Но, в отличии от обычных ссылок/указателей, weak_ptr предоставляет дополнительный сервис, заключающийся в том, что если хранимый в нем объект в какой-то момент времени удаляется «извне», то попытка получения его из weak_ptr приводит к исключению. Используется weak_ptr в случае, когда постоянное владение объектом не нужно, но, тем не менее, необходим прозрачный контроль над ним. Например:&lt;/p&gt;&lt;pre&gt;std::vector&amp;lt;boost::shared_ptr&amp;lt;SomeClass&amp;gt; &amp;gt; m_Vector;
std::map&amp;lt;std::string, boost::weak_ptr&amp;lt;SomeClass&amp;gt; &amp;gt; m_Map;
&lt;/pre&gt;&lt;p&gt;Предполагается, что m_Vector хранит и владеет экземплярами класса SomeClass, а m_Map – предоставляет быстрый доступ к этим объектам по некоторой строке. Инициализироваться они будут так:&lt;/p&gt;&lt;pre&gt;m_Vector.push_back(boost::shared_ptr&amp;lt;SomeClass&amp;gt;(new SomeClass));
m_Map.insert(std::make_pair(m_Vector.back()-&amp;gt;Key, m_Vector.back());
&lt;/pre&gt;&lt;p&gt;Теперь, если мы удалим какой-либо элемент из вектора, при попытке доступа к нему по ключу приведет к исключению. При этом дополнительных проверок на действительность ссылок делать не надо.&lt;/p&gt;&lt;h3&gt;intrusive_ptr&lt;/h3&gt;&lt;div&gt;    &lt;p&gt;Второй класс (boost::intrusive_ptr) используется при работе с объектами, использующими встроенный счетчик ссылок. Пример – COM-объекты. Этот класс предполагает, что определены функции intrusive_ptr_add_ref и intrusive_ptr_release (не являющиеся фунциями-членами хранимого класса), фактически увеличивающие или уменьшающие счетчик ссылок объекта. Для COM-объектов использование такого указателя могло бы выглядеть так:&lt;/p&gt;&lt;pre&gt;int intrusive_ptr_add_ref(IUnknown* p) {return p-&amp;gt;AddRef();}
int intrusive_ptr_release(IUnknown* p) {return p-&amp;gt;Release();}
&lt;/pre&gt;&lt;p&gt;после чего можно смело писать: boost::intrusive_ptr&amp;lt;ISomeInterface&amp;gt; ptr(…);&lt;/p&gt;&lt;p&gt;Этот класс имеет интерфейс, аналогичный классу boost::shared_ptr, за исключением того, что его нельзя использовать в связке с boost::weak_ptr. Функциональность описанных классов покрывает большинство задач, которые могут возникнуть при решении проблем с контролем указателей. Если же потребуется что-то специфическое (что мало вероятно) всегда можно изобрести свой собственный велосипед и использовать его. Приведенное описание не претендует на полноту. Были опущены некоторые моменты, связанные с использованием классов, в частности класса weak_ptr. Для получения более полной информации можно заглянуть непосредственно в документацию: &lt;a href="http://www.boost.org/libs/smart_ptr/smart_ptr.htm" title="http://www.boost.org/libs/smart_ptr/smart_ptr.htm" rel="nofollow"&gt;http://www.boost.org/libs/smart_ptr/smart_ptr.htm&lt;/a&gt;&lt;/p&gt;&lt;p&gt;P.S.: Наглым образом спёрто отсюда: &lt;a href="http://www.sources.ru/wiki/doku.php?id=doc:cpp:boost:shared_ptr"&gt;[[doc:cpp:boost:shared_ptr]]&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;!--EndFragment--&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1252038906587337119-2229152132418543560?l=rakafon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rakafon.blogspot.com/feeds/2229152132418543560/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://rakafon.blogspot.com/2009/04/boost.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/2229152132418543560'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/2229152132418543560'/><link rel='alternate' type='text/html' href='http://rakafon.blogspot.com/2009/04/boost.html' title='Использование интеллектуальных указателей из boost'/><author><name>Rakafon</name><uri>http://www.blogger.com/profile/03386514126069055282</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-wnns05XIxW4/Ti7XTMmujOI/AAAAAAAAABg/rZpn54sM7BI/s1600/20168127'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1252038906587337119.post-5486887258858118817</id><published>2009-04-01T21:50:00.001+03:00</published><updated>2010-10-15T14:36:27.797+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='boost'/><category scheme='http://www.blogger.com/atom/ns#' term='cpp'/><title type='text'>Использование boost::bind</title><content type='html'>&lt;p&gt;Одним из самых мощных средств стандартной библиотеки языка являются алгоритмы. Их в &lt;acronym title="Standard Template Library"&gt;STL&lt;/acronym&gt; много. А там, где алгоритмы – появляются функторы и их разновидности – предикаты. И все было бы замечательно, если бы не одна большая ложка дегтя – средства стандартной библиотеки предоставляют слишком мало возможностей для описания функуторов. Все просто, если в алгоритм необходимо передать какую-либо глобальную функцию, или простой указатель на метод класса, хранящегося в контейнере. &lt;/p&gt;&lt;p&gt;Но когда речь заходит о чем-то более сложном, как-то:  &lt;ul&gt;&lt;li&gt; передача заданного значения в предикат;  &lt;/li&gt;
&lt;li&gt; передача указателя на метод класса, не являющегося членом контейнера; &lt;/li&gt;
&lt;li&gt; предварительная обработка элементов контейнера перед передачей их в функтор; &lt;/li&gt;
&lt;li&gt; передача в функтор значений элементов данных объектов обрабатываемой последовательности; &lt;/li&gt;
&lt;li&gt; (список можно продолжить…) &lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;то &lt;acronym title="Standard Template Library"&gt;STL&lt;/acronym&gt; уже не может предложить чего-либо более-менее пригодного к использованию. Сразу же оказывается, что &lt;strong&gt;std::binder1st&lt;/strong&gt; и &lt;strong&gt;std::binder2nd&lt;/strong&gt; накладывают существенные ограничения на принимаемые параметры (кто не сталкивался с «reverence to reference is not allowed» при использовании их в связке с mem_fun_ref?), в стандартные предикаты нельзя передать результат выполнения некоторой операции над элементом контейнера, &lt;strong&gt;std::mem_fun&lt;/strong&gt; и &lt;strong&gt;std::mem_fun_ref&lt;/strong&gt; позволяют работать только с объектами, являющимися членами обрабатываемой последовательности… Вообщем мрак. Проблемы некоторым образом решаются с помощью написания собственных функторов и адаптеров функторов. Но разработка минимально необходимого джентльменского набора – сама по себе нетривиальная задача. Тем более, что она уже имеет весьма элегантное решение, называемое &lt;strong&gt;boost::bind.&lt;/strong&gt;  Без преувеличения можно сказать, что по сравнению со связкой boost::bind/boost::mem_fn близкие по функциональности классы из &lt;acronym title="Standard Template Library"&gt;STL&lt;/acronym&gt; кажутся жалкой поделкой. И не без основания. При использовании классов из &lt;acronym title="Standard Template Library"&gt;STL&lt;/acronym&gt; приходится всякий раз задумываться – а какой из вариантов связывателя подойдет к данному конкретному случаю, и подойдет ли вообще. С boost::bind о подобных вещах заморачиваться не надо. К каждому варианту использования компилятор самостоятельно подберет необходимый связыватель. Или выдаст ошибку, если соответствующего варианта подобрать нельзя.  В коде использовать этот класс не просто, а очень просто. Рассмотрим несколько типовых вариантов.  &lt;/p&gt;&lt;h2&gt;Использование с глобальной функцией&lt;/h2&gt;&lt;p&gt;Предположим, что есть функция: &lt;/p&gt;&lt;pre&gt;bool compare&amp;#40;int a, int b&amp;#41; &amp;#123;return a &amp;lt; b;&amp;#125;&lt;/pre&gt;&lt;p&gt;для того, чтобы использовать эту функцию в, например, алгоритме sort нам необходимо написать: &lt;/p&gt;&lt;pre&gt;std::vector&amp;lt;int&amp;gt; vec&amp;#40;…&amp;#41;;
std::sort&amp;#40;vec.begin&amp;#40;&amp;#41;, vec.end&amp;#40;&amp;#41;, compare&amp;#41;;&lt;/pre&gt;&lt;p&gt;Теперь немного усложним задачу – в зависимости от флага нам необходимо сортировать либо по возрастанию, либо по убыванию. При использовании только &lt;acronym title="Standard Template Library"&gt;STL&lt;/acronym&gt; пришлось бы писать две функции. Накладно. С помощью boost эту задачу решить значительно проще: &lt;/p&gt;&lt;pre&gt;bool compare&amp;#40;int a, int b, bool reverseSort&amp;#41; &amp;#123;return reverseSort ? a &amp;gt; b : a &amp;lt; b;&amp;#125;

&amp;nbsp;
std::vector&amp;lt;int&amp;gt; vec&amp;#40;…&amp;#41;;
std::sort&amp;#40;vec.begin&amp;#40;&amp;#41;, vec.end&amp;#40;&amp;#41;, boost::bind&amp;#40;compare, _1, _2, order&amp;#41;&amp;#41;;&lt;/pre&gt;&lt;p&gt;где order – булевская переменная, задающая порядок сортировки. Последняя строчка выглядит несколько странновато, но именно в ней и заключается вся суть. В результате ее компиляции будет получен код, реализующий сортировку массива, использующий для сравнения функцию compare, и передающей ей на вход три аргумента – два числа, которые необходимо сравнить, и способ их сравнения. Почему именно так? Рассмотрим этот код подробнее, записав его так: &lt;/p&gt;&lt;pre&gt;int a = 1, b = 2;
boost::bind&amp;#40;compare, _1, _2, false&amp;#41;&amp;#40;a, b&amp;#41;;&lt;/pre&gt;&lt;p&gt;(что-то подобное содержится в недрах функции std::sort). Последняя строчка в этом коде обозначает следующее: &lt;/p&gt;&lt;p&gt;boost::bind – функция, создающая необходимый нам связыватель. Возвращает экземпляр функционального объекта (функтора), для которого применим оператор вызова функции. (compare, - первый аргумент функции определяет имя/указатель на функцию, которая должна быть вызвана в связывателе. В данном случае это функция compare; _1, _2 – плейсхолдеры, определяющие логику передачи параметров из оператора вызова функции в функцию compare. , false) – значение последнего аргумента, передаваемого в compare. (a, b) – оператор вызова функции, производящий связывание аргументов и вызов функции compare. В итоге будет выполнена следующий код: &lt;/p&gt;&lt;p&gt;compare(a, b, false); &lt;/p&gt;&lt;p&gt;Из приведенного примера можно увидеть, что упомянутые выше плейсхолдеры определяют связь между аргументами у оператора вызова функции связывателя и аргументами вызываемой функцией. Причем, количество аргументов у оператора вызова функции связывателя определяется количеством плейсхолдеров: &lt;/p&gt;&lt;pre&gt;boost::bind&amp;#40;compare, _1, 4, false&amp;#41;&amp;#40;a, b&amp;#41;; // неправильно. 

boost::bind&amp;#40;compare, _1, 4, false&amp;#41;&amp;#40;a&amp;#41;; // правильно
boost::bind&amp;#40;compare, _1, _2, false&amp;#41;&amp;#40;a&amp;#41;; // неправильно

boost::bind&amp;#40;compare, _1, _2, false&amp;#41;&amp;#40;a, b&amp;#41;; // правильно&lt;/pre&gt;&lt;p&gt;Очевидно, что попытка задать в вызове boost::bind количество параметров, несоответствующее количеству обязательных параметров в вызываемой функции приведет к ошибке. Равно как и попытка указания количества параметров большего, чем количество параметров в вызываемой функции. Действуя по аналогии мы можем записать: &lt;/p&gt;&lt;pre&gt;std::find_if&amp;#40;vec.begin&amp;#40;&amp;#41;, vec.end&amp;#40;&amp;#41;, boost::bind&amp;#40;compare, _1, 4, false&amp;#41;&amp;#41;; // поиск первого числа, меньшего 4

std::remove_if&amp;#40;vec.begin&amp;#40;&amp;#41;, vec.end&amp;#40;&amp;#41;, boost::bind&amp;#40;compare, _1, 4, true&amp;#41;&amp;#41;; // удаление из последовательности всех элементов, больших 4

// и т. д.&lt;/pre&gt;&lt;p&gt;В случае использования чистого &lt;acronym title="Standard Template Library"&gt;STL&lt;/acronym&gt; для каждого случая пришлось бы искать подходящий функтор… Или писать его. Здесь необходимо обратить внимание на то, что в качестве первого параметра функции bind может выступать не только указатель на функцию, но и другой функциональный объект. Например: &lt;/p&gt;&lt;pre&gt;std::find_if&amp;#40;vec.begin&amp;#40;&amp;#41;, vec.end&amp;#40;&amp;#41;, boost::bind&amp;#40;std::equal_to&amp;lt;int&amp;gt;&amp;#40;&amp;#41;, _1, 4&amp;#41;&amp;#41;;&lt;/pre&gt;&lt;p&gt; этот строчка найдет в массиве первый элемент, равный 4.  &lt;/p&gt;&lt;h2&gt;Использование с указателями на функции члены&lt;/h2&gt;&lt;p&gt;Помимо указателей на глобальные функции и функторов, в качестве первого параметра можно указывать указатель на функцию-член какого-то класса. Предположим один из простейших вариантов использования: &lt;/p&gt;&lt;pre&gt;class GraphicsObject

&amp;#123;
public:
   void Draw&amp;#40;Canvas* canvas, DrawModes mode&amp;#41;;
&amp;#125;;
// Объявляем коллекцию объектов этого класса:
std::list&amp;lt;GraphicsObject*&amp;gt; GraphObjects;

// А теперь нам нужно отрисовать все объекты коллекции на заданном канвасе
std::for_each&amp;#40;GraphObjects.begin&amp;#40;&amp;#41;, GraphObjects.end&amp;#40;&amp;#41;; ……..&amp;#41;;&lt;/pre&gt;&lt;p&gt;при использовании чистого &lt;acronym title="Standard Template Library"&gt;STL&lt;/acronym&gt; нам бы пришлось писать свой собственный функтор, вызывающий у переданного объекта метод Draw с заданными параметрами. Но можно воспользоваться boost::bind:  &lt;/p&gt;&lt;pre&gt;std::for_each&amp;#40;GraphObjects.begin&amp;#40;&amp;#41;, GraphObjects.end&amp;#40;&amp;#41;, 
    boost::bind&amp;#40;&amp;amp;GraphObject::Draw, _1, canvas, mode&amp;#41;&amp;#41;;&lt;/pre&gt;&lt;p&gt;в результате чего мы получаем требуемый результат. У всех объектов коллекции вызывается метод Draw, которому передаются параметры canvas и mode. При использовании указателя на функцию-член класса необходимо помнить о том, что первым параметром ей должен передаваться указатель на объект, для которого эта функция должна вызываться. В приведенном примере мы указываем, что метод должен вызываться у переданного в bind единственного параметра. Но никто не мешает нам в качестве первого передаваемого параметра указать this, или любой другой указатель. Но, как говориться в современных набивших оскомину рекламах, это еще не все.  &lt;/p&gt;&lt;h2&gt;Использование с указателем на член данных&lt;/h2&gt;&lt;p&gt;Помимо указателей на члены-функции можно использовать указатели на члены данных. Синтаксис подобный и правила использования при этом почти такие же. Возьмем задачу. Есть структура и вектор ее экземпляров:  &lt;/p&gt;&lt;pre&gt;struct Point
&amp;#123;

    int x;
    int y;
&amp;#125;;
&amp;nbsp;
std::vector&amp;lt;Point&amp;gt; PointsArray;&lt;/pre&gt;&lt;p&gt; Теперь надо удалить из этого массива все элементы, у которых координата x равна нулю. Сделать это просто: &lt;/p&gt;&lt;pre&gt;std::remove_if&amp;#40;PointsArray.begin&amp;#40;&amp;#41;, PointsArray.end&amp;#40;&amp;#41;, 
    boost::bind&amp;#40;std::equal_to&amp;lt;int&amp;gt;&amp;#40;&amp;#41;, boost::bind&amp;#40;&amp;amp;Point::x, _1&amp;#41;, 0&amp;#41;&amp;#41;;&lt;/pre&gt;&lt;p&gt;Т. е. для  каждого элемента массива вызывается вложенный связыватель, который возвращает значение соответствующего элемента структуры, после чего производится его сравнение с нулем.  Тут мы видим еще одну возможность связывателей: &lt;/p&gt;&lt;h2&gt;Каскадное использование связывателей&lt;/h2&gt;&lt;p&gt;Связыватели могут вкладываться друг в друга. Один из вариантов такого вкладывания проиллюстрирован предыдущем примером. Единственное, что в этом случае надо «держать в голове» - это то, что плейсхолдеры, вне зависимости от того, в каком bind&amp;#039;ере (по уровню вложенности) они находятся,  «адресуют» параметры самого внешго binder&amp;#039;а. Усложним предыдущий пример. Нужно выбросить все точки, имеющие нулевые координаты:  &lt;/p&gt;&lt;pre&gt;std::remove_if&amp;#40; PointsArray.begin&amp;#40;&amp;#41;, PointsArray.end&amp;#40;&amp;#41;, boost::bind&amp;#40;

    std::logical_and&amp;#40;&amp;#41;, 
        boost::bind&amp;#40;std::equal_to&amp;lt;int&amp;gt;&amp;#40;&amp;#41;, boost::bind&amp;#40;&amp;amp;Point::x, _1&amp;#41;, 0&amp;#41;,
        boost::bind&amp;#40;std::equal_to&amp;lt;int&amp;gt;&amp;#40;&amp;#41;, boost::bind&amp;#40;&amp;amp;Point::y, _1&amp;#41;, 0&amp;#41;

    &amp;#41;
&amp;#41;&amp;#41;;&lt;/pre&gt;&lt;p&gt; Это хотя и работает так, как хочется, но выглядит слишком наворочено. По этому начиная с версии 1.33 в boost::bind появилась новая возможность -  &lt;/p&gt;&lt;h2&gt;Перегруженные операторы&lt;/h2&gt;&lt;p&gt; Для упрощения приведенных выше многоэтажных конструкций для boost::bind (начиная с версии 1.33 boost&amp;#039;а) перегружены следующие операторы: &lt;strong&gt;!&lt;/strong&gt;, &lt;strong&gt;==&lt;/strong&gt;, &lt;strong&gt;!=&lt;/strong&gt;, &lt;strong&gt;&amp;lt;&lt;/strong&gt;, &lt;strong&gt;?&lt;/strong&gt;, &lt;strong&gt;&amp;gt;&lt;/strong&gt; и &lt;strong&gt;&amp;gt;=&lt;/strong&gt;.  Таким образом, приведенное выше выражение упрощается до:  &lt;/p&gt;&lt;pre&gt;std::remove_if&amp;#40; PointsArray.begin&amp;#40;&amp;#41;, PointsArray.end&amp;#40;&amp;#41;, boost::bind&amp;#40;

    boost::bind&amp;#40;&amp;amp;Point::x, _1&amp;#41; == 0 &amp;amp;&amp;amp; boost::bind&amp;#40;&amp;amp;Point::y, _1&amp;#41; == 0&amp;#41;

    &amp;#41;&amp;#41;;&lt;/pre&gt;&lt;h2&gt;Использование ссылок&lt;/h2&gt;&lt;p&gt; Одна из неприятностей заключается в том, что если связываемая функция принимает какой-то из своих аргументов по ссылке, то с использованием boost::bind его (напрямую) передать нельзя. Т. е. например, в следующем случае:   &lt;/p&gt;&lt;pre&gt;void foo&amp;#40;int&amp;amp; a, int&amp;amp; b&amp;#41;;

&amp;nbsp;
int a = 1, b = 2;
boost::bind&amp;#40;foo, a, b&amp;#41;;&lt;/pre&gt;&lt;p&gt; аргументы a и b по ссылке переданы не будут. Для того, чтобы действительно передать ссылки, необходимо делать такой вызов:  &lt;/p&gt;&lt;pre&gt;boost::bind&amp;#40;foo, boost::ref&amp;#40;a&amp;#41;, boost::ref&amp;#40;b&amp;#41;&amp;#41;;&lt;/pre&gt;&lt;p&gt; В этом случае foo, вызываемый из связывателя, будет действительно работать со ссылками на соответствующие переменные. &lt;/p&gt;&lt;p&gt;Полную документацию и примеры использования можно найти в оригинальной документации: &lt;a href="http://www.boost.org/libs/bind/bind.html" title="http://www.boost.org/libs/bind/bind.html" rel="nofollow"&gt;http://www.boost.org/libs/bind/bind.html&lt;/a&gt;  &lt;/p&gt;&lt;h2&gt;Пример использования.&lt;/h2&gt;&lt;pre&gt;#include &amp;lt;vector&amp;gt;
#include &amp;lt;boost/bind.hpp&amp;gt;
#include &amp;lt;boost/function.hpp&amp;gt;

class Test
{
public:
    void f_1()
    {
        std::cout &amp;lt;&amp;lt; "void f()" &amp;lt;&amp;lt; std::endl;
    }

    void f_2(int i)
    {
        std::cout &amp;lt;&amp;lt; "void f_2(): " &amp;lt;&amp;lt; i &amp;lt;&amp;lt; std::endl;
    }

    void f_3(const int &amp;i)
    {
        std::cout &amp;lt;&amp;lt; "void f_2(): " &amp;lt;&amp;lt; i &amp;lt;&amp;lt; std::endl;
    }

    void two_params(int a, int b)
    {
        std::cout &amp;lt;&amp;lt; "void two_params(int a, int b): " &amp;lt;&amp;lt; a &amp;lt;&amp;lt; ", " &amp;lt;&amp;lt; b &amp;lt;&amp;lt; std::endl;
    }
};

class Test2
{
public:
    void do_stuff(const std::vector&amp;lt;int&amp;gt;&amp; v) 
    {
        std::copy(v.begin(), v.end(),  std::ostream_iterator&amp;lt;int&amp;gt;(std::cout, " "));
    }
};

void test(const std::string &amp;a)
{
    std::cout &amp;lt;&amp;lt; "void test(const std::string &amp;a). a = " &amp;lt;&amp;lt; a &amp;lt;&amp;lt; std::endl;
}

void prn ( boost::function&amp;lt;void(int)&amp;gt; fn, int a )
{
    fn ( a );
}

int _tmain(int argc, _TCHAR* argv[])
{
    ////////////////////// bind //////////////////////
    std::cout &amp;lt;&amp;lt; "boost::bind test" &amp;lt;&amp;lt; std::endl;
    Test a;
    boost::bind(&amp;Test::f_1, &amp;a)();

    boost::bind(&amp;Test::f_2, &amp;a, 1)();
    int test_int(2);
    boost::bind(&amp;Test::f_2, &amp;a, _1)(test_int);

    boost::bind(&amp;Test::f_3, &amp;a, 3)();
    int test_int_2(4);
    boost::bind(&amp;Test::f_3, &amp;a, _1)(test_int_2);

    int one(100), two(200);
    boost::bind(&amp;Test::two_params, &amp;a, _1, _2)(one, two);
    boost::bind(&amp;Test::two_params, &amp;a, _2, _1)(one, two);

    std::string test_str("Hi there.");
    boost::bind(&amp;test, test_str)();
    boost::bind(&amp;test, _1)(test_str);
    std::cout &amp;lt;&amp;lt; std::endl;
    
    ////////////////////// function //////////////////////
    std::cout &amp;lt;&amp;lt; "boost::function test" &amp;lt;&amp;lt; std::endl;
    
    boost::function&amp;lt;void (void)&amp;gt; func;
    func = boost::bind(&amp;Test::f_1, &amp;a);
    func();
    func = boost::bind(&amp;Test::f_2, &amp;a, 201);
    func();
    func = boost::bind(&amp;Test::f_3, &amp;a, 202);
    func();
    func = boost::bind(&amp;Test::two_params, &amp;a, 203, 204);
    func();

    boost::function&amp;lt;void (int)&amp;gt; func_2;
    func_2 = boost::bind(&amp;Test::f_2, &amp;a, _1);
    prn(func_2, 301);
    func_2 = boost::bind(&amp;Test::f_3, &amp;a, _1);
    prn(func_2, 302);

    int i_303(303), i_304(304), i_305(305), i_306(306);
    func_2 = boost::bind(&amp;Test::two_params, &amp;a, i_303, _1);
    prn(func_2, 1);
    func_2 = boost::bind(&amp;Test::two_params, &amp;a, _1, i_304);
    prn(func_2, 1);

    Test2 t;
    std::vector&amp;lt;int&amp;gt; vec;
    vec.resize(20);
    std::generate_n(vec.begin(), 20, rand);
    std::copy(vec.begin(), vec.end(),  std::ostream_iterator&amp;lt;int&amp;gt;(std::cout, " "));
    //simple_bind(&amp;Test::do_stuff, t, _1)(vec);
    //boost::bind(&amp;Test2::do_stuff, t, _1)(vec);

    return 0;
}
&lt;/pre&gt;&lt;p&gt;P.S.: Наглым образом спёрто здесь: &lt;a href="http://www.sources.ru/wiki/doku.php?id=doc:cpp:boost:bind"&gt;[[doc:cpp:boost:bind]]&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1252038906587337119-5486887258858118817?l=rakafon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rakafon.blogspot.com/feeds/5486887258858118817/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://rakafon.blogspot.com/2009/04/boostbind.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/5486887258858118817'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/5486887258858118817'/><link rel='alternate' type='text/html' href='http://rakafon.blogspot.com/2009/04/boostbind.html' title='Использование boost::bind'/><author><name>Rakafon</name><uri>http://www.blogger.com/profile/03386514126069055282</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-wnns05XIxW4/Ti7XTMmujOI/AAAAAAAAABg/rZpn54sM7BI/s1600/20168127'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1252038906587337119.post-4106403431309468139</id><published>2009-04-01T21:40:00.001+03:00</published><updated>2010-10-15T14:36:32.741+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='boost'/><category scheme='http://www.blogger.com/atom/ns#' term='cpp'/><title type='text'>Использование boost::function</title><content type='html'>&lt;p&gt;Во многих современных языках существует понятие «делегата» - некоторой сущности, позволяющей косвенно вызвать тот или иной метод. Наиболее близкая аналогия в С++ - это указатель на функцию или член класса. Но каждый разработчик на С++, кто сталкивался с такого рода указателями, в итоге выясняет, что они - не полноценный аналог делегата. По двум причинам:&lt;/p&gt;&lt;div&gt;Указатель на функцию и указатель на член класса не могут быть преобразованы друг в друга.&lt;/div&gt;&lt;div&gt;Для доступа к члену класса по указателю обязательно требуется указатель на объект, относительно которого производится вызов.&lt;/div&gt;&lt;p&gt;А по этому, если указатели на свободные функции или статические функции еще можно как-то рассматривать в качестве делегатов, то с указателями на члены класса все гозаздо сложнее. Для устранения этих проблем и был создан шаблонный класс boost::function (а точнее - набор шаблонных классов).&lt;/p&gt;&lt;p&gt;Что это такое? По сути - boost::function (точнее, результат его инстанцирования) - это функтор (функциональный объект), к которому применим оператор »()» (вызова функции). А потому в исходный тексте программы вызов метода напрямую или через boost::function ничем не отличимы.&lt;/p&gt;&lt;p&gt;В качестве аргументов шаблона boost::function принимает сигнатуру метода, который он будет «эмулировать». Например:&lt;/p&gt;&lt;pre&gt;boost::function&amp;lt;void ()&amp;gt; foo1;
// (соответствует методу с сигнатурой void foo1();)

boost::function&amp;lt;int (int, float, SomeClass&amp;amp;)&amp;gt; foo2;
// соответствует методу
// int foo2(int arg1, float arg2, SomeClass&amp;amp; arg3)

// и т. д.
&lt;/pre&gt;&lt;p&gt;А инициализироваться может либо указателем на соответствующий метод, либо другим функциональным объектом, который может быть вызван с указанными параметрами:&lt;/p&gt;&lt;pre&gt;void foo1(int a) {;}

struct Foo1
{
   void operator() (int a) {;}
}

boost::function&amp;lt;void (int)&amp;gt; Delegate;

//...
Delegate = foo1;
// ...
Delegate(10); // будет реально вызван foo1(10)
// ...
// ...
Delegate = Foo1();
// ...
Delegate(10); // будет вызван Foo1::operator()(10);
&lt;/pre&gt;&lt;h3&gt;Как это использовать&lt;/h3&gt;&lt;p&gt;boost::function можно использовать:&lt;/p&gt;&lt;div&gt;Со свободными (глобальными) функциями.&lt;/div&gt;&lt;div&gt;С функциями-членами.&lt;/div&gt;&lt;div&gt;С функциональными объектами.&lt;/div&gt;&lt;p&gt;Синтаксис объявления экземпляра boost::function не меняется. Аргументы, которые может принимать boost::function такие же, какие может принимать обычная функция. При этом (как и для обычной функции) можно перечислять как просто типы аргументов, так и типы с формальными именами параметров:&lt;/p&gt;&lt;pre&gt;// оба объявления равноценны
boost::function&amp;lt;void (int, float[], SomeClass&amp;amp;)&amp;gt; f1;
boost::function&amp;lt;void (int a, float arr[], SomeClass&amp;amp; sc)&amp;gt; f2;
&lt;/pre&gt;&lt;p&gt;Максимальное количество аргументов, которое может принимать boost::function зависит от реализации. Чаще всего - не больше 10.&lt;/p&gt;&lt;p&gt;После объявления экземпляра boost::function его необходимо обязательно заполнить (проинициализировать). До этого момента экземпляр будет считаться «пустым» и при попытки применить к нему оператор вызова функции будет выброшено исключение bad_function_call.&lt;/p&gt;&lt;h2&gt;Использование вместе со свободными функциями&lt;/h2&gt;&lt;p&gt;Для использования boost::function совместно со свободными функциями достаточно проинициализировать объект адресом соответствующей функции:&lt;/p&gt;&lt;pre&gt;void foo(int, int) {;}

boost::function&amp;lt;void (int, int)&amp;gt; f1;
f1 = foo;
// или
f1 = &amp;amp;foo;
&lt;/pre&gt;&lt;h2&gt;Использование вместе с функциями-членами&lt;/h2&gt;&lt;p&gt;Используется также, как и со свободными функциями:&lt;/p&gt;&lt;pre&gt;class SomeClass
{
public:
 void foo(int, int) {;}
}

boost::function&amp;lt;void (int, int)&amp;gt; f1;
f1 = &amp;amp;SomeClass::foo;
&lt;/pre&gt;&lt;p&gt;Но использование такого функционального объекта требует передачи ему экземпляра класса, для которого должна быть вызвана функция:&lt;/p&gt;&lt;pre&gt;SomeClass obj;
f1(&amp;amp;obj, 10);
&lt;/pre&gt;&lt;p&gt;В случае необходимости передачи «чистого» функционального объекта ситуацию спасает использование boost::bind, или std::bind1st:&lt;/p&gt;&lt;pre&gt;SomeClass* obj = ...;
f1 = boost::bind(&amp;amp;SomeClass::foo, obj, _1);
//...
f1(10); // эквивалентен вызову f1 из предыдущего примера
&lt;/pre&gt;&lt;p&gt;Статические функции члены передаются в boost::function также, как и свободные функции.&lt;/p&gt;&lt;h2&gt;Использование с функциональными объектами&lt;/h2&gt;&lt;p&gt;Если для какого-то объекта можно применить оператор вызова функции, то он также, как и обычные функции, может быть использован для инициализации boost::function. Пример был приведен в предыдущем разделе, когда boost::function инициализировался функциональным объектом boost::bind.&lt;/p&gt;&lt;p&gt;Поскольку функциональный объект в boost::function хранится по значению, то в случае необходимости передачи ссылки необходимо воспользоваться boost::ref:&lt;/p&gt;&lt;pre&gt;SomeFunctionObject foo;
boost::function&amp;lt;void (int)&amp;gt; f1;
f1 = boost::ref(foo);
boost::function&amp;lt;void (int)&amp;gt; f2;
f2(f1);
&lt;/pre&gt;&lt;p&gt;В этом случае f1 и f2 будут использовать для работы один и тот же функциональный объект.&lt;/p&gt;&lt;p&gt;P.S.: Наглым образом спёрто отсюда: &lt;a href="http://www.sources.ru/wiki/doku.php?id=doc:cpp:boost:function"&gt;[[doc:cpp:boost:function]]&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1252038906587337119-4106403431309468139?l=rakafon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rakafon.blogspot.com/feeds/4106403431309468139/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://rakafon.blogspot.com/2009/04/boostfunction.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/4106403431309468139'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/4106403431309468139'/><link rel='alternate' type='text/html' href='http://rakafon.blogspot.com/2009/04/boostfunction.html' title='Использование boost::function'/><author><name>Rakafon</name><uri>http://www.blogger.com/profile/03386514126069055282</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-wnns05XIxW4/Ti7XTMmujOI/AAAAAAAAABg/rZpn54sM7BI/s1600/20168127'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1252038906587337119.post-661300680308240842</id><published>2009-04-01T21:20:00.001+03:00</published><updated>2010-10-15T14:40:37.899+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='boost'/><category scheme='http://www.blogger.com/atom/ns#' term='cpp'/><title type='text'>Использование boost:array</title><content type='html'>&lt;p&gt;Данный класс представляет собой STL-совместимый контейнер для массивов с постоянным размером.&lt;/p&gt;&lt;p&gt;Разработан Николаи Джоссатисом (автором таких книг как C++ Standard Library и C++ Templates)&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;h3&gt;Описание.&lt;/h3&gt;&lt;br /&gt;
&lt;h4&gt;Конструктор.&lt;/h4&gt;&lt;pre&gt;template&amp;lt;typename U&amp;gt;
array&amp;amp; operator=(const array&amp;lt;U, N&amp;gt;&amp;amp; other);
&lt;/pre&gt;&lt;p&gt;Создаёт экземпляр объекта array&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Итераторы.&lt;/h4&gt;&lt;pre&gt;iterator begin();
const_iterator begin() const;
&lt;/pre&gt;&lt;p&gt;Представляют соответственно неконстантный и константный итераторы для первого элемента array.&lt;/p&gt;&lt;pre&gt;iterator end();
const_iterator end() const;
&lt;/pre&gt;&lt;p&gt;Представляют соответственно неконстантный и константный итераторы для конечного элемента array.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Обратные итераторы.&lt;/h4&gt;&lt;pre&gt;iterator rbegin();
const_iterator rbegin() const;
&lt;/pre&gt;&lt;p&gt;Представляют соответственно обратные неконстантный и константный итераторы для первого элемента array.&lt;/p&gt;&lt;pre&gt;iterator rend();
const_iterator rend() const;
&lt;/pre&gt;&lt;p&gt;Представляют соответственно обратные неконстантный и константный итераторы для конечного элемента array.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Ёмкость.&lt;/h4&gt;&lt;pre&gt;array size_type size();
&lt;/pre&gt;&lt;p&gt;Возвращает число элементов array&lt;/p&gt;&lt;pre&gt;bool empty();
&lt;/pre&gt;&lt;p&gt;Если array пустой возвращает true.&lt;/p&gt;&lt;pre&gt;size_type max_size();
&lt;/pre&gt;&lt;p&gt;Возвращает максимальное число элементов.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Доступ к элементам array.&lt;/h4&gt;&lt;pre&gt;reference operator[](size_type i);
const_reference operator[](size_type i) const;
&lt;/pre&gt;&lt;p&gt;Возвращает элемент с индексом i.&lt;/p&gt;&lt;p&gt;В случает доступа к элементу с несуществующим индексом исключения не вызывается.&lt;/p&gt;&lt;pre&gt;reference at(size_type i);
const_reference at(size_type i) const;
&lt;/pre&gt;&lt;p&gt;Возвращает элемент с индексом i.&lt;/p&gt;&lt;p&gt;В случает доступа к элементу с несуществующим индексом вызывается исключение std::range_error.&lt;/p&gt;&lt;pre&gt;reference front();
const_reference front() const;
&lt;/pre&gt;&lt;p&gt;Возвращает первый элемент.&lt;/p&gt;&lt;pre&gt;reference back();
const_reference back() const;
&lt;/pre&gt;&lt;p&gt;Возвращает последний элемент.&lt;/p&gt;&lt;pre&gt;T* c_array();
const T* data() const;
&lt;/pre&gt;&lt;p&gt;Возвращает указатель на массив элементов типа T.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Модификаторы array.&lt;/h4&gt;&lt;pre&gt;void swap(array&amp;lt;T, N&amp;gt;&amp;amp; other);
&lt;/pre&gt;&lt;p&gt;Обмен элементами между двумя объектами типа array.&lt;/p&gt;&lt;pre&gt;void assign(const T&amp;amp; value);
&lt;/pre&gt;&lt;p&gt;Заполнить array элементами из другого объектаСпециализированные алгоритмы&lt;/p&gt;&lt;pre&gt;template&amp;lt;typename T, std::size_t N&amp;gt;
void swap(array&amp;lt;T, N&amp;gt;&amp;amp; x, array&amp;lt;T, N&amp;gt;&amp;amp; y);
&lt;/pre&gt;&lt;p&gt;Обмен элементами между двумя объектами типа array.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Операторы сравнения для array.&lt;/h4&gt;&lt;pre&gt;template&amp;lt;typename T, std::size_t N&amp;gt;
bool operator==(const array&amp;lt;T, N&amp;gt;&amp;amp; x, const array&amp;lt;T, N&amp;gt;&amp;amp; y);
template&amp;lt;typename T, std::size_t N&amp;gt;
bool operator!=(const array&amp;lt;T, N&amp;gt;&amp;amp; x, const array&amp;lt;T, N&amp;gt;&amp;amp; y);
template&amp;lt;typename T, std::size_t N&amp;gt;
bool operator&amp;lt;(const array&amp;lt;T, N&amp;gt;&amp;amp; x, const array&amp;lt;T, N&amp;gt;&amp;amp; y);
template&amp;lt;typename T, std::size_t N&amp;gt;
bool operator&amp;gt;(const array&amp;lt;T, N&amp;gt;&amp;amp; x, const array&amp;lt;T, N&amp;gt;&amp;amp; y);
template&amp;lt;typename T, std::size_t N&amp;gt;
bool operator&amp;lt;=(const array&amp;lt;T, N&amp;gt;&amp;amp; x, const array&amp;lt;T, N&amp;gt;&amp;amp; y);
template&amp;lt;typename T, std::size_t N&amp;gt;
bool operator&amp;gt;=(const array&amp;lt;T, N&amp;gt;&amp;amp; x, const array&amp;lt;T, N&amp;gt;&amp;amp; y);
&lt;/pre&gt;&lt;!--EndFragment--&gt; &lt;p&gt;P.S.: Нагло спёрто отсюда: &lt;a href="http://forum.vingrad.ru/faq/topic-157819.html"&gt;forum.vingrad.ru -&amp;gt; Boost:Array&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1252038906587337119-661300680308240842?l=rakafon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rakafon.blogspot.com/feeds/661300680308240842/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://rakafon.blogspot.com/2009/04/boostarray.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/661300680308240842'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/661300680308240842'/><link rel='alternate' type='text/html' href='http://rakafon.blogspot.com/2009/04/boostarray.html' title='Использование boost:array'/><author><name>Rakafon</name><uri>http://www.blogger.com/profile/03386514126069055282</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-wnns05XIxW4/Ti7XTMmujOI/AAAAAAAAABg/rZpn54sM7BI/s1600/20168127'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1252038906587337119.post-963012942478903830</id><published>2009-04-01T21:00:00.001+03:00</published><updated>2010-10-15T14:37:01.798+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='boost'/><category scheme='http://www.blogger.com/atom/ns#' term='cpp'/><title type='text'>Использование характеристик типов boost/type_traits.hpp</title><content type='html'>&lt;hr width="75%" align="left"&gt;&lt;h3&gt;Содержание&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;a href="#intro"&gt;Вступление&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="#primary"&gt;Первоначальная категоризация типов&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="#secondary"&gt;Вторичная категоризация типов&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="#properties"&gt;Свойства типов&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="#relationships"&gt;Отношения между типами&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="#transformations"&gt;Преобразования между типами&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="#synthesized"&gt;Синтезирование типов&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="#function_traits"&gt;Свойства функций&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="#headers"&gt;Заголовочные файлы свойств типов&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="#specializations"&gt;Пользовательские специализации&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="#examples"&gt;Примеры&lt;/a&gt;&lt;br /&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;hr width="75%" align="left"&gt;&lt;h3&gt;&lt;a name="intro"&gt;&lt;/a&gt;Вступление&lt;/h3&gt;&lt;p&gt;Содержимое (классы) заголовочного файла &amp;lt;boost/type_traits.hpp&amp;gt; объявляется в пространстве имен boost.&lt;/p&gt;&lt;p&gt;В файле &amp;lt;boost/type_traits.hpp&amp;gt; определены три вида &lt;i&gt;свойств типов&lt;/i&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt; свойства выбранного типа &lt;/li&gt;
&lt;li&gt; отношения между двумя типами&lt;/li&gt;
&lt;li&gt; преобразования от одного типа к другому&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Если Вы ранее не работали с этой библиотекой, то предлагаем ознакомиться со &lt;a href="http://www.solarix.ru/for_developers/cpp/boost/type_traits/ru/c++_type_traits.shtml"&gt;статьей&lt;/a&gt;, где описываются основы и цели создания библиотеки.&lt;/p&gt;&lt;p&gt;Все целочисленные выражения в данной библиотеке являются константами времени компиляции, что иногда может вызвать проблемы с используемым компилятором.&lt;/p&gt;&lt;h3&gt;&lt;a name="primary"&gt;&lt;/a&gt;Первичная категоризация типов&lt;/h3&gt;&lt;p&gt;Нижеследующие шаблоны свойств типов позволяют определить, к какой категории типов принадлежит заданный тип. Для любого заданного типа только одно выражение получит значение true. Заметьте, что &lt;code&gt;is_integral&amp;lt;T&amp;gt;::value&lt;/code&gt; и &lt;code&gt;is_float&amp;lt;T&amp;gt;::value&lt;/code&gt; будут true только для встроенных типов; если есть необходимость проверки для пользовательских типов так же, как для встроенных, то следует использовать шаблон std::numeric_limits.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;::boost::is_void&amp;lt;T&amp;gt;::value&lt;/strong&gt;&lt;/code&gt;&lt;br /&gt;
становится true только если T является cv-qualified void типом.&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;&lt;code&gt;::boost::is_float&amp;lt;T&amp;gt;::value&lt;/strong&gt;&lt;/code&gt;&lt;br /&gt;
становится true только если T является cv-qualified типом с плавающей точкой&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;&lt;code&gt;::boost::is_integral&amp;lt;T&amp;gt;::value&lt;/strong&gt;&lt;/code&gt;&lt;strong&gt;&lt;code&gt;&lt;br /&gt;
&lt;/strong&gt;&lt;/code&gt;становится true только если T является cv-qualified целым типом.&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;&lt;code&gt;::boost::is_float&amp;lt;T&amp;gt;::value&lt;/strong&gt;&lt;/code&gt;&lt;strong&gt;&lt;code&gt;&lt;br /&gt;
&lt;/strong&gt;&lt;/code&gt;становится true только если T является cv-qualified типом с плавающей точкой&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;&lt;code&gt;::boost::is_pointer&amp;lt;T&amp;gt;::value&lt;/strong&gt;&lt;/code&gt;&lt;strong&gt;&lt;code&gt;&lt;br /&gt;
&lt;/strong&gt;&lt;/code&gt;становится true только если T является cv-qualified указателем (включая указатели на функции, но исключая указатели на члены классов).&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;&lt;code&gt;::boost::is_reference&amp;lt;T&amp;gt;::value&lt;/strong&gt;&lt;/code&gt;&lt;strong&gt;&lt;code&gt;&lt;br /&gt;
&lt;/strong&gt;&lt;/code&gt;становится true только если T является ссылкой.&lt;br /&gt;
если компилятор не поддерживает частичную специализацию шаблонов классов, тогда этот шаблон может давать неправильные результаты.&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;&lt;code&gt;::boost::is_member_pointer&amp;lt;T&amp;gt;::value&lt;/strong&gt;&lt;/code&gt;&lt;strong&gt;&lt;code&gt;&lt;br /&gt;
&lt;/strong&gt;&lt;/code&gt;становится true только если T является a cv-qualified указателем на член класса (поле класса или метод).&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;&lt;code&gt;::boost::is_array&amp;lt;T&amp;gt;::value&lt;/strong&gt;&lt;/code&gt;&lt;strong&gt;&lt;code&gt;&lt;br /&gt;
&lt;/strong&gt;&lt;/code&gt;становится true только если T является массивом.&lt;br /&gt;
если компилятор не поддерживает частичную специализацию шаблонов классов, тогда этот шаблон может давать неправильные результаты.&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;&lt;code&gt;::boost::is_union&amp;lt;T&amp;gt;::value&lt;/strong&gt;&lt;/code&gt;&lt;strong&gt;&lt;code&gt;&lt;br /&gt;
&lt;/strong&gt;&lt;/code&gt;становится true только если T является типом union. В настоящее время требуется некоторая поддержка со стороны компилятора, иначе union'ы рассматриваются как классы.&lt;br /&gt;
Без определенной помощи со стороны компилятора (в настоящее время данная возможность не стандартизована), мы не можем отличить union от класса, в результате чего выражение никогда не получается true.&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;&lt;code&gt;::boost::is_class&amp;lt;T&amp;gt;::value&lt;/strong&gt;&lt;/code&gt;&lt;strong&gt;&lt;code&gt;&lt;br /&gt;
&lt;/strong&gt;&lt;/code&gt;становится true только если T является классом или структурой.&lt;br /&gt;
Без определенной помощи со стороны компилятора (в настоящее время данная возможность не стандартизована), мы не можем отличать union от классов, в результате чего выражение дает неправильный ответ true для аргумента типа union.&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;&lt;code&gt;::boost::is_enum&amp;lt;T&amp;gt;::value&lt;/strong&gt;&lt;/code&gt;&lt;strong&gt;&lt;code&gt;&lt;br /&gt;
&lt;/strong&gt;&lt;/code&gt;становится true только если T является перечислением (enum).&lt;br /&gt;
требуется правильно работающий шаблон is_convertible (это означает, что шаблон is_enum в настоящее время не работает в Borland C++ Builder 5, и в некоторых версиях компилятора Metrowerks).&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;&lt;code&gt;::boost::is_function&amp;lt;T&amp;gt;::value&lt;/strong&gt;&lt;/code&gt;&lt;strong&gt;&lt;code&gt;&lt;br /&gt;
&lt;/strong&gt;&lt;/code&gt;становится true только если T является функциональным типом (но не ссылкой и не указателем на функцию).&lt;br /&gt;
если компилятор не поддерживает частичную специализацию шаблонов классов, тогда этот шаблон не компилируется для ссылочных типов.&lt;/li&gt;

&lt;/ul&gt;&lt;h3&gt;&lt;a name="properties"&gt;&lt;/a&gt;Свойства типов&lt;/h3&gt;&lt;p&gt;Нижеописанные шаблоны идентифицируют свойства, которые имеет заданный тип.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;&lt;strong&gt;::boost::alignment_of&amp;lt;T&amp;gt;::value&lt;/strong&gt;&lt;/code&gt;&lt;br /&gt;
идентифицирует величину выравнивания для T. в действительности возвращает величину, которая гарантированно является множителем действительной величины выравнивания. T должен быть полностью определен (complete type)&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;::boost::is_empty&amp;lt;T&amp;gt;::value&lt;/strong&gt;&lt;/code&gt; &lt;br /&gt;
true если T является пустой структурой или классом. Если компилятор поддерживает метод оптимизации &amp;quot;пустые базовые классы нулевого размера&amp;quot;, тогда шаблон is_empty может правильно определить, что T пустой. Используется шаблон is_class для определения, когда T является классом. &lt;br /&gt;
T должен быть полностью определен (complete type)&lt;br /&gt;
Компилятор должен поддерживать реализацию пустых базовых классов нулевого размера, чтобы обнаружение пустых классов работало.&lt;br /&gt;
Не может быть использован с неопределенными полностью типами.&lt;br /&gt;
Не может работать с union'ами до тех пор, пока шаблон is_union сможет работать (см. его описание).&lt;br /&gt;
Если компилятор не поддерживает частичную специализацию шаблонов классов, тогда этот шаблон не может быть использован с абстрактными типами.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;::boost::is_const&amp;lt;T&amp;gt;::value&lt;/strong&gt;&lt;/code&gt;&lt;br /&gt;
true только если &amp;nbsp;T квалифицирован как const (top-level const-qualified).&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;::boost::is_volatile&amp;lt;T&amp;gt;::value&lt;/strong&gt;&lt;/code&gt;&lt;br /&gt;
true только если &amp;nbsp;T квалифицирован как volatile.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;::boost::is_polymorphic&amp;lt;T&amp;gt;::value&lt;/strong&gt;&lt;/code&gt;&lt;br /&gt;
true только если &amp;nbsp;T является полиморфным типом.&lt;br /&gt;
T должен быть полностью определен (complete type)&lt;br /&gt;
Требуется знание ABI компилятора, в действительности шаблон работоспособен на большинстве существующих компиляторов.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;::boost::is_pod&amp;lt;T&amp;gt;::value&lt;/strong&gt;&lt;/code&gt;&lt;br /&gt;
true только если &amp;nbsp;T является cv-qualified POD, то есть простой структурой без методов, с возможными квалификаторами const и volatile.&lt;br /&gt;
T должен быть полностью определен (complete type).&lt;br /&gt;
Без некоторой помощи (в настоящее время эти возможности не стандартизованы) со стороны компилятора, шаблон is_pod не может определить, что T является POD; это безопасно, хотя может быть не оптимальным.&lt;br /&gt;
Если компилятор не поддерживает частичную специализацию шаблонов классов, то данный шаблон не может быть использован с функциональными типами.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;::boost::has_trivial_constructor&amp;lt;T&amp;gt;::value&lt;/strong&gt;&lt;/code&gt;&lt;br /&gt;
true если T имеет простой деструктор, сгенерированный компилятором (trivial default constructor).&lt;br /&gt;
Без некоторой помощи (в настоящее время эти возможности не стандартизованы) со стороны компилятора, шаблон has_trivial_constructor не сможет определить, что заданный тип имеет пустой конструктор. Это всегда безопасно, хотя может быть неоптимальным.&lt;br /&gt;
Если компилятор не поддерживает частичную специализацию шаблонов классов, то данный шаблон не может быть использован с функциональными типами.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;::boost::has_trivial_copy&amp;lt;T&amp;gt;::value&lt;/strong&gt;&lt;/code&gt;&lt;br /&gt;
true если T имеет простой сгенерированный компилятором конструктор копирования ( trivial copy constructor).&lt;br /&gt;
T должен быть полностью определен (complete type).&lt;br /&gt;
Без некоторой помощи (в настоящее время эти возможности не стандартизованы) со стороны компилятора, шаблон &lt;code&gt;&lt;strong&gt;has_trivial_copy &lt;/strong&gt;&lt;/code&gt;&amp;nbsp;не сможет определить, что заданный тип имеет пустой конструктор копирования. Это всегда безопасно, хотя может быть неоптимальным.&lt;br /&gt;
Если компилятор не поддерживает частичную специализацию шаблонов классов, то данный шаблон не может быть использован с функциональными типами.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;::boost::has_trivial_assign&amp;lt;T&amp;gt;::value&lt;/strong&gt;&lt;/code&gt;&lt;br /&gt;
true если T имеет простой сгенерированный компилятором оператор присваивания (trivial assignment operator).&lt;br /&gt;
T должен быть полностью определен (complete type).&lt;br /&gt;
Без некоторой помощи (в настоящее время эти возможности не стандартизованы) со стороны компилятора, шаблон &lt;code&gt;&lt;strong&gt;has_trivial_assign &lt;/strong&gt;&lt;/code&gt;&amp;nbsp;не сможет определить, что заданный тип имеет пустой оператор присваивания. Это всегда безопасно, хотя может быть неоптимальным.&lt;br /&gt;
Если компилятор не поддерживает частичную специализацию шаблонов классов, то данный шаблон не может быть использован с функциональными типами.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;::boost::has_trivial_destructor&amp;lt;T&amp;gt;::value&lt;/strong&gt;&lt;/code&gt;&lt;br /&gt;
true если T имеет простой, сгенерированный деструктор (trivial destructor).&lt;br /&gt;
T должен быть полностью определен (complete type).&lt;br /&gt;
Без некоторой помощи (в настоящее время эти возможности не стандартизованы) со стороны компилятора, шаблон &lt;code&gt;&lt;strong&gt;&amp;nbsp;has_trivial_destructor &lt;/strong&gt;&lt;/code&gt;не сможет определить, что заданный тип имеет пустой оператор присваивания. Это всегда безопасно, хотя может быть неоптимальным.&lt;br /&gt;
Если компилятор не поддерживает частичную специализацию шаблонов классовв, то данный шаблон не может быть использован с функциональными типами.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;::boost::is_stateless&amp;lt;T&amp;gt;::value&lt;/strong&gt;&lt;/code&gt;&lt;br /&gt;
true если T не имеет состояния, то есть T не выделяет память и его конструкторы и деструктор сгенерированы компилятором.&lt;br /&gt;
T должен быть полностью определен (complete type).&lt;br /&gt;
Без некоторой помощи (в настоящее время эти возможности не стандартизованы) со стороны компилятора, шаблон &lt;code&gt;&lt;strong&gt;is_stateless &lt;/strong&gt;&lt;/code&gt;не сможет определить, что заданный тип не имеет состояния. Это всегда безопасно, хотя может быть неоптимальным.&lt;br /&gt;
Выражение становится true только если становятся true все нижеуказанные:&lt;br /&gt;
&lt;code&gt;&lt;strong&gt;::boost::has_trivial_constructor&amp;lt;T&amp;gt;::value,&lt;/strong&gt;&lt;/code&gt;&lt;br /&gt;
&lt;code&gt;&lt;strong&gt;::boost::has_trivial_copy&amp;lt;T&amp;gt;::value,&lt;/strong&gt;&lt;/code&gt;&lt;br /&gt;
&lt;code&gt;&lt;strong&gt;::boost::has_trivial_destructor&amp;lt;T&amp;gt;::value,&lt;/strong&gt;&lt;/code&gt;&lt;br /&gt;
&lt;code&gt;&lt;strong&gt;::boost::is_class&amp;lt;T&amp;gt;::value,&lt;/strong&gt;&lt;/code&gt;&lt;br /&gt;
&lt;code&gt;&lt;strong&gt;::boost::is_empty&amp;lt;T&amp;gt;::value&lt;/strong&gt;&lt;/code&gt;&lt;br /&gt;
Если компилятор не поддерживает частичную специализацию шаблонов классов, то данный шаблон не может быть использован с функциональными типами.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;::boost::has_nothrow_constructor&amp;lt;T&amp;gt;::value&lt;/strong&gt;&lt;/code&gt;&lt;br /&gt;
true если T имеет конструктор по умолчанию, не генерирующий исключения.&lt;br /&gt;
T должен быть полностью определен (complete type).&lt;br /&gt;
Без некоторой помощи (в настоящее время эти возможности не стандартизованы) со стороны компилятора, шаблон &lt;code&gt;&lt;strong&gt;&amp;nbsp;has_nothrow_constructor &lt;/strong&gt;&lt;/code&gt;не сможет определить, что заданный тип имеет конструктор, не генерирующий исключения. Это всегда безопасно, хотя может быть неоптимальным.&lt;br /&gt;
Если компилятор не поддерживает частичную специализацию шаблонов классов, то данный шаблон не может быть использован с функциональными типами.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;::boost::has_nothrow_copy&amp;lt;T&amp;gt;::value&lt;/strong&gt;&lt;/code&gt;&lt;br /&gt;
true если T имеет конструктор копирования, не генерирущий исключений.&lt;br /&gt;
T должен быть полностью определен (complete type).&lt;br /&gt;
Без некоторой помощи (в настоящее время эти возможности не стандартизованы) со стороны компилятора, шаблон &lt;code&gt;&lt;strong&gt;has_nothrow_copy &lt;/strong&gt;&lt;/code&gt;не сможет определить, что заданный тип имеет конструктор копирования, не генерирующий исключения. Это всегда безопасно, хотя может быть неоптимальным.&lt;br /&gt;
Если компилятор не поддерживает частичную специализацию шаблонов классов, то данный шаблон не может быть использован с функциональными типами.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;::boost::has_nothrow_assign&amp;lt;T&amp;gt;::value&lt;/strong&gt;&lt;/code&gt;&lt;br /&gt;
true если T имеет оператор присваивания, не генерирующий исключений.&lt;br /&gt;
T должен быть полностью определен (complete type).&lt;br /&gt;
Без некоторой помощи (в настоящее время эти возможности не стандартизованы) со стороны компилятора, шаблон &lt;code&gt;&lt;strong&gt;&amp;nbsp;has_nothrow_assign &lt;/strong&gt;&lt;/code&gt;не сможет определить, что заданный тип имеет оператор присваивания, не генерирующий исключения. Это всегда безопасно, хотя может быть неоптимальным.&lt;br /&gt;
Если компилятор не поддерживает частичную специализацию шаблонов классов, то данный шаблон не может быть использован с функциональными типами.&lt;/li&gt;

&lt;/ul&gt;&lt;h3&gt;&lt;a name="relationships"&gt;&lt;/a&gt;Отношения между типами&lt;/h3&gt;&lt;p&gt;Следующая таблица содержит шаблоны, с помощью которых можно выяснить, есть ли какая-либо зависимость между двумя типами:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;::boost::is_same&amp;lt;T,U&amp;gt;::value&lt;br /&gt;
&lt;/code&gt;&lt;/strong&gt;становится true, если T и U - один и тот же тип.&lt;br /&gt;
Если компилятор не поддерживает частичную специализацию шаблонов классов, тогда этот шаблон не может быть использован с &amp;nbsp;абстрактными, неполностью определенными или функциональными типами.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;::boost::is_convertible&amp;lt;T,U&amp;gt;::value&lt;/strong&gt;&lt;/code&gt;&lt;strong&gt;&lt;br /&gt;
&lt;/strong&gt;становится true, если воображаемый объект типа &amp;nbsp;T может быт преобразован в тип U.&lt;br /&gt;
Тип T не должен быть неполностью определенным типом.&lt;br /&gt;
Тип U не должен быть неполностью определенным, либо абстрактным типом, либо функциональным типом.&lt;br /&gt;
Подразумевается, что никакой тип не может быть преобразован в массив.&lt;br /&gt;
Обратите внимание, что данный шаблон работает неправильно с Borland C++ Builder 5 (и более ранними версиями) для преобразований через конструкторы, для с компилятором Metrowerks 7 (и более ранними версиями) во всех случаях.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;::boost::is_base_and_derived&amp;lt;T,U&amp;gt;::value&lt;/strong&gt;&lt;/code&gt;&lt;strong&gt;&lt;br /&gt;
&lt;/strong&gt;становится true, если T является базовым классом для типа U.&lt;br /&gt;
Будут обнаружены не-публичные базовые классы, и неоднозначные базовые классы.&lt;br /&gt;
Обратите внимание, что любой класс не рассматривается как собственный базовый класс. Аналогично, если T или U не являются классами, тогда результат будет в любом случае false.&lt;br /&gt;
Типы T и U не должны быть неполностью описанными.&lt;br /&gt;
Если компилятор не поддерживает частичную специализацию шаблонов классов, тогда этот шаблон не может быть использован с функциональными типами.&lt;/li&gt;

&lt;/ul&gt;&lt;p&gt;Обратите внимание, что как &lt;code&gt;is_convertible&lt;/code&gt;, так и &lt;code&gt; is_base_and_derived&lt;/code&gt; могут привести к ошибке компиляции, если преобразование неоднозначно.:&lt;/p&gt;&lt;pre&gt;struct A {};
struct B : A {};
struct C : A {};
struct D : B, C {};
bool const x = boost::is_base_and_derived&amp;lt;A,D&amp;gt;::value;  // ошибка
bool const y = boost::is_convertible&amp;lt;D*,A*&amp;gt;::value;     // ошибка
&lt;/pre&gt;&lt;h3&gt;&lt;a name="transformations"&gt;&lt;/a&gt;Преобразования между типами&lt;/h3&gt;&lt;p&gt;Следующие шаблоны преобразовывают один тип в другой, основываясь на простом правиле: каждый шаблон имеет единственный член &lt;i&gt;type&lt;/i&gt;, который является результатом применения преобразования к аргументу шаблона T:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;&lt;strong&gt;::boost::remove_const&amp;lt;T&amp;gt;::type&lt;/strong&gt;&lt;/code&gt;&lt;strong&gt;&lt;br /&gt;
&lt;/strong&gt;Создает тип такой же как T, но убирает квалификатор const самого верхнего уровня. К примеру, &amp;quot;const int&amp;quot; становится&amp;quot;int&amp;quot;, но &amp;quot;const int*&amp;quot; остается неизменным.&lt;br /&gt;
Если компилятор не поддерживает частичную специализацию шаблонов классов, тогда этот шаблон компилируется, но не работает, за исключением случаев, указанных в примечании ниже.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;::boost::remove_volatile&amp;lt;T&amp;gt;::type&lt;/strong&gt;&lt;/code&gt;&lt;strong&gt;&lt;br /&gt;
&lt;/strong&gt;Создает тип такой же как T, но убирает квалификатор volatile самого верхнего уровня. К примеру, &amp;quot;volatile int&amp;quot; становится &amp;quot;int&amp;quot;.&lt;br /&gt;
Если компилятор не поддерживает частичную специализацию шаблонов классов, тогда этот шаблон компилируется, но не работает, за исключением случаев, указанных в примечании ниже.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;::boost::remove_cv&amp;lt;T&amp;gt;::type&lt;/strong&gt;&lt;/code&gt;&lt;strong&gt;&lt;br /&gt;
&lt;/strong&gt;Создает тип такой же как T, но убирает квалификаторы const и volatile самого верхнего уровня. К примеру &amp;quot;const volatile int&amp;quot; становится &amp;quot;int&amp;quot;.&lt;br /&gt;
Если компилятор не поддерживает частичную специализацию шаблонов классов, тогда этот шаблон компилируется, но не работает, за исключением случаев, указанных в примечании ниже.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;::boost::remove_reference&amp;lt;T&amp;gt;::type&lt;/strong&gt;&lt;/code&gt;&lt;strong&gt;&lt;br /&gt;
&lt;/strong&gt;Если T является ссылкой, тогда удаляет ссылку, иначе тип T остается неизменным. К примеру, &amp;quot;int&amp;amp;&amp;quot; становится &amp;quot;int&amp;quot;, но &amp;quot;int*&amp;quot; не изменится.&lt;br /&gt;
Если компилятор не поддерживает частичную специализацию шаблонов классов, тогда этот шаблон компилируется, но не работает, за исключением случаев, указанных в примечании ниже.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;::boost::remove_bounds&amp;lt;T&amp;gt;::type&lt;/strong&gt;&lt;/code&gt;&lt;strong&gt;&lt;br /&gt;
&lt;/strong&gt;Если T является типом массива, тогда удаляет квалификатор верхнего уровня массива, в противном случае T не изменяется. К примеру, &amp;nbsp;&amp;quot;int[2][3]&amp;quot; становится &amp;quot;int[3]&amp;quot;.&lt;br /&gt;
если компилятор не поддерживает частичную специализацию шаблонов классов, тогда этот шаблон компилируется, но не работает.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;::boost::remove_pointer&amp;lt;T&amp;gt;::type&lt;/strong&gt;&lt;/code&gt;&lt;strong&gt;&lt;br /&gt;
&lt;/strong&gt;Если T является указателем, тогда удаляет указатель верхнего уровня (top-level indirection) у T, иначе T остается неизменным. К примеру, &amp;quot;int*&amp;quot; становится &amp;quot;int&amp;quot;, но &amp;quot;int&amp;amp;&amp;quot; не меняется.&lt;br /&gt;
Если компилятор не поддерживает частичную специализацию шаблонов классов, тогда этот шаблон компилируется, но не работает, за исключением случаев, указанных в примечании ниже.&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;::boost::add_reference::type&lt;br /&gt;
&lt;/strong&gt;Если T является ссылкой, тогда тип T не меняется, иначе преобразует T в ссылку. К примеру, &amp;quot;int&amp;amp;&amp;quot; не меняется, а &amp;nbsp;&amp;quot;double&amp;quot; становится &amp;quot;double&amp;amp;&amp;quot;.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;::boost::add_pointer&amp;lt;T&amp;gt;::type&lt;/strong&gt;&lt;/code&gt;&lt;strong&gt;&lt;br /&gt;
&lt;/strong&gt;Результатом работы является тип, который получается как &lt;code&gt;&amp;nbsp;remove_reference&amp;lt;T&amp;gt;::type*&lt;/code&gt;. К примеру, &amp;quot;int&amp;quot; и &amp;quot;int&amp;amp;&amp;quot; становятся &amp;quot;int*&amp;quot;.&lt;br /&gt;
Если компилятор не поддерживает частичную специализацию шаблонов классов, тогда этот шаблон на компилируется с ссылочными типами.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;::boost::add_const&amp;lt;T&amp;gt;::type&lt;/strong&gt;&lt;/code&gt;&lt;br /&gt;
То же, что &amp;quot;T const&amp;quot; для всех T.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;::boost::add_volatile&amp;lt;T&amp;gt;::type&lt;/strong&gt;&lt;/code&gt;&lt;br /&gt;
То же, что &amp;quot;T volatile&amp;quot; для всех T.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;::boost::add_cv&amp;lt;T&amp;gt;::type&lt;/strong&gt;&lt;/code&gt;&lt;strong&gt;&lt;br /&gt;
&lt;/strong&gt;То же, что &amp;quot;T const volatile&amp;quot; для всех T.&lt;/li&gt;

&lt;/ul&gt;&lt;p&gt;Как видно по данной таблице, поддержка частичной специализации шаблонов классов необходима для правильной реализации шаблоном преобразования типов. С другой стороны, практика показывает, что многие шаблоны из данной категории очень полезны, и зачастую жизненно необходимы для реализации некоторых обобщенных библиотек (generic libraries). Отсутствие этих шаблонов часто является одним из главных ограничивающих факторов в портировании таких библиотек для компиляторов, которые все еще не поддерживают необходимые возможности языка C++. Поскольку некоторые из этих компиляторов будут использоваться еще какое-то время, а по крайней мере один из них широко распространен, было решено, что библиотека должна содержать решение проблемы, когда это возможно. Основной способ решения такой:&lt;/p&gt;&lt;ol&gt;&lt;li&gt; Вручную создать полные специализации шаблонов для всех типов преобразований для всех фундаментальных типов, а также всех их указателей (* и **) с/без квалификаторами const     и volatile &lt;/li&gt;
&lt;li&gt; Создать пользовательские макросы, которые будут определять такие явные специализации для любого пользовательского типа&amp;nbsp; T.&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;Первый пункт гарантирует успешную компиляцию такого фрагмента:&lt;/p&gt;&lt;pre&gt;BOOST_STATIC_ASSERT((is_same&amp;lt;char, remove_reference&amp;lt;char&amp;amp;&amp;gt;::type&amp;gt;::value));
BOOST_STATIC_ASSERT((is_same&amp;lt;char const, remove_reference&amp;lt;char const&amp;amp;&amp;gt;::type&amp;gt;::value));
BOOST_STATIC_ASSERT((is_same&amp;lt;char volatile, remove_reference&amp;lt;char volatile&amp;amp;&amp;gt;::type&amp;gt;::value));
BOOST_STATIC_ASSERT((is_same&amp;lt;char const volatile, remove_reference&amp;lt;char const volatile&amp;amp;&amp;gt;::type&amp;gt;::value));
BOOST_STATIC_ASSERT((is_same&amp;lt;char*, remove_reference&amp;lt;char*&amp;amp;&amp;gt;::type&amp;gt;::value));
BOOST_STATIC_ASSERT((is_same&amp;lt;char const*, remove_reference&amp;lt;char const*&amp;amp;&amp;gt;::type&amp;gt;::value));
....
BOOST_STATIC_ASSERT((is_same&amp;lt;char const volatile* const volatile* const volatile, remove_reference&amp;lt;char const volatile* const volatile* const volatile&amp;amp;&amp;gt;::type&amp;gt;::value));&lt;/pre&gt;&lt;p&gt;и второй пункт обеспечивает для пользователей библиотеки механизм, с помощью которого вышеприведенный код будет работать не только для типов 'char', 'int' или других встроенных типов, но для любых пользовательских типов:&lt;/p&gt;&lt;pre&gt;struct my {};
BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION(my)
BOOST_STATIC_ASSERT((is_same&amp;lt;my, remove_reference&amp;lt;my&amp;amp;&amp;gt;::type&amp;gt;::value));
BOOST_STATIC_ASSERT((is_same&amp;lt;my, remove_const&amp;lt;my const&amp;gt;::type&amp;gt;::value));
// etc.&lt;/pre&gt;&lt;p&gt;Заметьте, что макрос BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION становится пустым для компиляторов, которые не поддерживают частичную специализацию.&lt;/p&gt;&lt;h3&gt;&lt;a name="synthesized"&gt;&lt;/a&gt;Синтезирование типов&lt;/h3&gt;&lt;p&gt;Следующие шаблоны синтезируют типы с желаемыми свойствами. &lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;&lt;strong&gt;::boost::type_with_alignment&amp;lt;Align&amp;gt;::type&lt;/strong&gt;&lt;/code&gt;&lt;strong&gt;&lt;br /&gt;
&lt;/strong&gt;&lt;/li&gt;

пытается найти встроенный тип или POD, который имеет значение выравнивания такое же, как множитель заданного параметр а Align. &lt;/ul&gt;&lt;h3&gt;&lt;a name="function_traits"&gt;&lt;/a&gt;Свойства функций&lt;/h3&gt;&lt;p&gt;Шаблон класса &lt;code&gt;::boost::function_traits&lt;/code&gt; извлекает информацию о функциональном типе. &lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;&lt;strong&gt;::boost::function_traits&amp;lt;F&amp;gt;::arity&lt;/strong&gt;&lt;/code&gt;&lt;strong&gt;&lt;br /&gt;
&lt;/strong&gt;определяет арность функционального типа &lt;code&gt;F&lt;/code&gt;.&lt;br /&gt;
Без поддержки частичной специализации данный шаблон не компилируется для ссылочных типов.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;::boost::function_traits&amp;lt;F&amp;gt;::result_type&lt;/strong&gt;&lt;/code&gt;&lt;strong&gt;&lt;br /&gt;
&lt;/strong&gt;тип, возвращаемый функциональным типом &lt;code&gt;&amp;nbsp;F&lt;/code&gt;.&lt;br /&gt;
Не компилируется без поддержки частичной специализации шаблонов классов.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;::boost::function_traits&amp;lt;F&amp;gt;::arg&lt;/strong&gt;&lt;em&gt;&lt;strong&gt;N&lt;/strong&gt;&lt;/em&gt;&lt;strong&gt;_type&lt;/strong&gt;&lt;/code&gt;&lt;strong&gt;&lt;br /&gt;
&lt;/strong&gt;тип &lt;code&gt;&lt;em&gt;N&lt;/em&gt;&lt;/code&gt;го аргумента функции &lt;code&gt;F&lt;/code&gt;, где &lt;code&gt;1&amp;lt;=&lt;em&gt;N&lt;/em&gt;&amp;lt;=арность(F)&lt;/code&gt;.&lt;br /&gt;
Не компилируется без поддержки частичной специализации шаблонов классов.&lt;/li&gt;

&lt;/ul&gt;&lt;h3&gt;&lt;a name="compiler"&gt;&lt;/a&gt;&lt;a name="headers"&gt;&lt;/a&gt;Заголовочные файлы свойств типов&lt;/h3&gt;&lt;p&gt;Библиотека свойств типов нормально подключается заголовочным файлом:&lt;/p&gt;&lt;pre&gt;#include &amp;lt;boost/type_traits.hpp&amp;gt;&lt;/pre&gt;&lt;p&gt;Однако в действительности библиотека разбита на ряд небольших файлов, так что иногда может быть удобнее включать один из этих файлов напрямую, чтобы получить только те шаблоны, которые нужны. Отдельные хидеры всегда имеют то же имя, что и соответствующий шаблон, и хранятся в каталоге boost/type_traits/.&amp;nbsp; Так что если, к примеру, некоторый код нуждается в шаблоне&amp;nbsp; is_class&amp;lt;&amp;gt;, тогда просто включайте:&lt;/p&gt;&lt;pre&gt;&amp;lt;boost/type_traits/is_class.hpp&amp;gt;&lt;/pre&gt;&lt;h3&gt;&lt;a name="specializations"&gt;&lt;/a&gt;Пользовательские специализации&lt;/h3&gt;&lt;p&gt;В ряде случаев конечный пользователь может нуждаться в собственных специализациях для какого-либо из шаблонов свойств типов - обычно когда используемый компилятор требует, чтобы соответствующее свойство типа было реализовано полностью.&amp;nbsp;Эти специализации должны наследовать от boost::mpl::true_ или boost::mpl::false_ соответственно:&lt;/p&gt;&lt;pre&gt;#  include &amp;lt;boost/type_traits/is_pod.hpp&amp;gt;
#  include &amp;lt;boost/type_traits/is_class.hpp&amp;gt;
#  include &amp;lt;boost/type_traits/is_union.hpp&amp;gt;

struct my_pod{};
struct my_union
{
char c;
int i;
};

namespace boost
{
template&amp;lt;&amp;gt;
struct is_pod&amp;lt;my_pod&amp;gt; 
: public mpl::true_{};
template&amp;lt;&amp;gt;
struct is_pod&amp;lt;my_union&amp;gt; 
: public mpl::true_{};
template&amp;lt;&amp;gt;
struct is_union&amp;lt;my_union&amp;gt; 
: public mpl::true_{};
template&amp;lt;&amp;gt;
struct is_class&amp;lt;my_union&amp;gt; 
: public mpl::false_{};
}

&lt;/pre&gt;&lt;h3&gt;&lt;a name="examples"&gt;&lt;/a&gt;Примеры&lt;/h3&gt;&lt;p&gt;Есть четыре примера работы с шаблонами свойств типов:&lt;/p&gt;&lt;h4&gt;Copy_example.cpp&lt;/h4&gt;&lt;p&gt;Демонстрируется версия std::copy, которая использует функцию memcpy, когда это возможно, для выполнения копирования (то есть если тип - один из фундаментальных, либо POD, и т.д.);&lt;/p&gt;&lt;pre&gt;//
// opt::copy
// same semantics as std::copy
// calls memcpy where appropiate.
//

namespace detail{

template&amp;lt;typename I1, typename I2&amp;gt;
I2 copy_imp(I1 first, I1 last, I2 out)
{
while(first != last)
{
*out = *first;
++out;
++first;
}
return out;
}

template &amp;lt;bool b&amp;gt;
struct copier
{
template&amp;lt;typename I1, typename I2&amp;gt;
static I2 do_copy(I1 first, I1 last, I2 out)
{ return copy_imp(first, last, out); }
};

template &amp;lt;&amp;gt;
struct copier&amp;lt;true&amp;gt;
{
template&amp;lt;typename I1, typename I2&amp;gt;
static I2* do_copy(I1* first, I1* last, I2* out)
{
memcpy(out, first, (last-first)*sizeof(I2));
return out+(last-first);
}
};


}

template&amp;lt;typename I1, typename I2&amp;gt;
inline I2 copy(I1 first, I1 last, I2 out)
{
typedef typename boost::remove_cv&amp;lt;typename std::iterator_traits&amp;lt;I1&amp;gt;::value_type&amp;gt;::type v1_t;
typedef typename boost::remove_cv&amp;lt;typename std::iterator_traits&amp;lt;I2&amp;gt;::value_type&amp;gt;::type v2_t;
return detail::copier&amp;lt;
::boost::type_traits::ice_and&amp;lt;
::boost::is_same&amp;lt;v1_t, v2_t&amp;gt;::value,
::boost::is_pointer&amp;lt;I1&amp;gt;::value,
::boost::is_pointer&amp;lt;I2&amp;gt;::value,
::boost::has_trivial_assign&amp;lt;v1_t&amp;gt;::value
&amp;gt;::value&amp;gt;::do_copy(first, last, out);
}&lt;/pre&gt;&lt;h4&gt;fill_example.cpp&lt;/h4&gt;&lt;p&gt;Демонстрируется версия std::fill, которая использует функцию memset, когда это возможно, для оптимизации операции заполнения. Также используется шаблон call_traits для оптимизации передачи параметров, чтобы избежать проблем с синонимами (aliasing issues):&lt;/p&gt;&lt;pre&gt;namespace opt{
///
// fill
// same as std::fill, uses memset where appropriate, along with call_traits
// to "optimise" parameter passing.
//
namespace detail{

template &amp;lt;typename I, typename T&amp;gt;
void do_fill_(I first, I last, typename boost::call_traits&amp;lt;T&amp;gt;::param_type val)
{
while(first != last)
{
*first = val;
++first;
}
}

template &amp;lt;bool opt&amp;gt;
struct filler
{
template &amp;lt;typename I, typename T&amp;gt;
struct rebind
{
static void do_fill(I first, I last, typename boost::call_traits&amp;lt;T&amp;gt;::param_type val)
{ do_fill_&amp;lt;I,T&amp;gt;(first, last, val); }
};
};

template &amp;lt;&amp;gt;
struct filler&amp;lt;true&amp;gt;
{
template &amp;lt;typename I, typename T&amp;gt;
struct rebind
{
static void do_fill(I first, I last, T val)
{
std::memset(first, val, last-first);
}
};
};

}

template &amp;lt;class I, class T&amp;gt;
inline void fill(I first, I last, const T&amp;amp; val)
{
typedef detail::filler&amp;lt;
::boost::type_traits::ice_and&amp;lt;
::boost::is_pointer&amp;lt;I&amp;gt;::value,
::boost::is_arithmetic&amp;lt;T&amp;gt;::value,
(sizeof(T) == 1)
&amp;gt;::value&amp;gt; filler_t;
typedef typename filler_t:: template rebind&amp;lt;I,T&amp;gt; binder;
binder::do_fill(first, last, val);
}
}};   // namespace opt&lt;/pre&gt;&lt;h4&gt;iter_swap_example.cpp&lt;/h4&gt;&lt;p&gt;Демонстрируется версия алгоритма std::iter_swap, который работает с прокси-итераторами (proxying iterators), а также с обычными итераторами; вызывает&amp;nbsp; std::swap для обычных итераторов, иначе выполняет медленный, но надежный обмен:&lt;/p&gt;&lt;pre&gt;namespace opt{
///
// iter_swap:
// tests whether iterator is a proxying iterator or not, and
// uses optimal form accordingly:
//
namespace detail{

template &amp;lt;bool b&amp;gt;
struct swapper
{
template &amp;lt;typename I&amp;gt;
static void do_swap(I one, I two)
{
typedef typename std::iterator_traits&amp;lt;I&amp;gt;::value_type v_t;
v_t v = *one;
*one = *two;
*two = v;
}
};

template &amp;lt;&amp;gt;
struct swapper&amp;lt;true&amp;gt;
{
template &amp;lt;typename I&amp;gt;
static void do_swap(I one, I two)
{
using std::swap;
swap(*one, *two);
}
};

}

template &amp;lt;typename I1, typename I2&amp;gt;
inline void iter_swap(I1 one, I2 two)
{
typedef typename std::iterator_traits&amp;lt;I1&amp;gt;::reference r1_t;
typedef typename std::iterator_traits&amp;lt;I2&amp;gt;::reference r2_t;
detail::swapper&amp;lt;
::boost::type_traits::ice_and&amp;lt;
::boost::is_reference&amp;lt;r1_t&amp;gt;::value, 
::boost::is_reference&amp;lt;r2_t&amp;gt;::value,
::boost::is_same&amp;lt;r1_t, r2_t&amp;gt;::value
&amp;gt;::value&amp;gt;::do_swap(one, two);
}

};   // namespace opt&lt;/pre&gt;&lt;h4&gt;Trivial_destructor_example.cpp&lt;/h4&gt;&lt;p&gt;Этот алгоритм выполняет обратную по отношению к std::unitialized_copy работу; он получает указатель на блок инициализированной памяти и вызывает деструкторы для каждого из объектов в нем. Это может быть использовано при реализации контейнерных классов, которые самостоятельно управляют своей памятью:&lt;/p&gt;&lt;pre&gt;namespace opt{
//
// algorithm destroy_array:
// The reverse of std::unitialized_copy, takes a block of
// initialized memory and calls destructors on all objects therein.
//

namespace detail{

template &amp;lt;bool&amp;gt;
struct array_destroyer
{
template &amp;lt;class T&amp;gt;
static void destroy_array(T* i, T* j){ do_destroy_array(i, j); }
};

template &amp;lt;&amp;gt;
struct array_destroyer&amp;lt;true&amp;gt;
{
template &amp;lt;class T&amp;gt;
static void destroy_array(T*, T*){}
};

template &amp;lt;class T&amp;gt;
void do_destroy_array(T* first, T* last)
{
while(first != last)
{
first-&amp;gt;~T();
++first;
}
}

}; // namespace detail

template &amp;lt;class T&amp;gt;
inline void destroy_array(T* p1, T* p2)
{
detail::array_destroyer&amp;lt;boost::has_trivial_destructor&amp;lt;T&amp;gt;::value&amp;gt;::destroy_array(p1, p2);
}
} // namespace opt&lt;/pre&gt;&lt;hr color="#c0c0c0" size="1"&gt; &lt;p&gt;P.S.: Нагло утянуто отсюда: &lt;a href="http://www.solarix.ru/for_developers/cpp/boost/type_traits/ru/index.shtml"&gt;Библиотека BOOST C++: заголовочный файл &amp;lt;boost/type_traits.hpp&amp;gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1252038906587337119-963012942478903830?l=rakafon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rakafon.blogspot.com/feeds/963012942478903830/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://rakafon.blogspot.com/2009/04/boosttypetraitshpp.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/963012942478903830'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/963012942478903830'/><link rel='alternate' type='text/html' href='http://rakafon.blogspot.com/2009/04/boosttypetraitshpp.html' title='Использование характеристик типов boost/type_traits.hpp'/><author><name>Rakafon</name><uri>http://www.blogger.com/profile/03386514126069055282</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-wnns05XIxW4/Ti7XTMmujOI/AAAAAAAAABg/rZpn54sM7BI/s1600/20168127'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1252038906587337119.post-2600091652917654673</id><published>2009-04-01T20:40:00.001+03:00</published><updated>2010-10-15T14:37:06.618+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='boost'/><category scheme='http://www.blogger.com/atom/ns#' term='cpp'/><title type='text'>Использование boost::static_assert</title><content type='html'>&lt;p &gt;Заголовочный файл &amp;lt;boost/static_assert.hpp&amp;gt;  содержит определение макроса BOOST_STATIC_ASSERT(x),  который генерирует сообщение об ошибке компиляции,  если целочисленное константное выражение &lt;i&gt;x&lt;/i&gt; не равно true. Другими словами,  это эквивалент макросу assert на стадии  компиляции; иногда эти средства называют &amp;quot;проверки во время компиляции&amp;quot;,  но здесь будут называться &amp;quot;статические проверки (static assertion)&amp;quot;.  Заметьте, что если условие равно  true, то макрос не генерирует ни кода, ни данных, а также то, что этот макрос может быть использован в области видимости имен (scope) пространства имен, класса или функции. будучи  использован в шаблоне, статическая проверка (static assertion) подставляется во  время конкретизации шаблона (instantiation); это  полезно для проверки параметров шаблона (см. -  &lt;a href="http://www.solarix.ru/for_developers/cpp/boost/type_traits/ru/index.shtml"&gt;свойства типов&lt;/a&gt;). &lt;/p&gt;&lt;lj-cut text="Читать дальше ..."&gt;  &lt;p &gt;Одной из целей создания BOOST_STATIC_ASSERT  была генерация читабельных сообщений об ошибках.  Эти сообщения непосредственно сообщают пользователю,  что библиотека используется способом, который не  поддерживается. Сообщения об ошибке варьируются для разных компиляторов, но Вы должны увидеть нечто вроде: &lt;/p&gt;&lt;pre&gt;Illegal use of COMPILE_TIME_ASSERTION_FAILURE&amp;lt;false&amp;gt;&lt;/pre&gt;&lt;p&gt;Это, по меньшей мере,  должно привлечь внимание!&lt;/p&gt;&lt;p &gt;Вы можете использовать макрос BOOST_STATIC_ASSERT  в любом месте кода, где синтаксически допустимо  поместить объявление, то есть в области видимости &lt;a href="#class"&gt;класса&lt;/a&gt;,   &lt;a href="#function"&gt;функции&lt;/a&gt; или &lt;a href="#namespace"&gt;пространства имен&lt;/a&gt;.  Эти варианту иллюстрируются следующими примерами:&lt;/p&gt;&lt;p &gt;&lt;a name="namespace"&gt;&lt;/a&gt;Использование в области видимости  пространства имен.&lt;/p&gt;&lt;p &gt;Макрос может быть использован в области видимости (scope) пространства имен (namespace), когда некое  требование должно быть удовлетворено; обычно это означает некоторые специфичные  для конкретной платформы требования. Допустим, нам  необходимо удостовериться, что тип  int имеет по крайней мере 32 бита, и что wchar_t является беззнаковым типом.  Мы можем проверить это во время компиляции таки образом:&lt;/p&gt;&lt;pre&gt;#include &amp;lt;climits&amp;gt;
#include &amp;lt;cwchar&amp;gt;
#include &amp;lt;boost/static_assert.hpp&amp;gt;

namespace my_conditions {

BOOST_STATIC_ASSERT(sizeof(int) * CHAR_BIT &amp;gt;= 32);
BOOST_STATIC_ASSERT(WCHAR_MIN &amp;gt;= 0);

} // namespace my_conditions
&lt;/pre&gt;&lt;p &gt;Такое использование пространства мен &lt;i&gt;my_conditions&lt;/i&gt;  требует некоторых пояснений. Макрос BOOST_STATIC_ASSERT  работает через объявление типа оператором &lt;strong&gt;typedef&lt;/strong&gt;, а так как &lt;b&gt;typedef&lt;/b&gt;   должен получить имя создаваемого синонима типа, то макрос создает это имя  автоматически путем комбинирования имени-заглушки (stub name) с макросом __LINE__. Когда макрос BOOST_STATIC_ASSERT  используется в области видимости класса или функции,  то каждое использование BOOST_STATIC_ASSERT  гарантированно дает уникальное для данной области видимости имя  (при условии, что макрос используется единожды в  каждой строке). Однако, при использовании макроса в  хидере в области видимости пространства имен, надо учесть,  что пространство имен может быть разбросано на множестве хидеров, каждый из которых может содержать собственные статические проверки (static assertions),  причем на одинаковых строках, что приведет к дублированию объявлений. В теории  компилятор должен молча игнорировать дубликаты для синонимов типов в &lt;b&gt;typedef&lt;/b&gt;, однако не все следуют этому правилу (и  даже если следуют, то иногда генерируют предупреждения  в таких случаях). Чтобы избежать потенциальных проблем, в хитере в области видимости пространства имен следует использовать  макрос BOOST_STATIC_ASSERT  внутри уникального для данного хидера пространства имен.&lt;/p&gt;&lt;p &gt;&lt;a name="function"&gt;&lt;/a&gt;Использование в области видимости  функции&lt;/p&gt;&lt;p &gt;Макрос обычно используется в области видимости внутри  шаблонной функции, когда необходимо проверять аргументы. Представьте, что у нас есть алгоритм, использующий итераторы, который требует  итераторы с произвольным доступом (random access iterators). Если данный  алгоритм будет конкретизирован (instantiated) с итератором, который не удовлетворяет такому условию, то  ошибка рано или поздно возникнет, но она возможно  появится в глубине нескольких подставляемых шаблонов,   что делает затруднительным для пользователя определить причину ошибки. Один из  методов решения - добавить статическую проверку на верхний уровень шаблона, так что если условие не соблюдается, то ошибка  генерируется способом, которые делает очевидным для  пользователя причину - неверное использование шаблона.&lt;/p&gt;&lt;pre&gt;#include &amp;lt;iterator&amp;gt;
#include &amp;lt;boost/static_assert.hpp&amp;gt;
#include &amp;lt;boost/type_traits.hpp&amp;gt;

template &amp;lt;class RandomAccessIterator &amp;gt;
RandomAccessIterator foo(RandomAccessIterator from, RandomAccessIterator to)
{
   // this template can only be used with
   // random access iterators...
   typedef typename std::iterator_traits&amp;lt; RandomAccessIterator &amp;gt;::iterator_category cat;
   BOOST_STATIC_ASSERT((boost::is_convertible&amp;lt;cat, const std::random_access_iterator_tag&amp;amp;&amp;gt;::value));
   //
   // detail goes here...
   return from;
}&lt;/pre&gt;&lt;p &gt;Вот парочка сносок по поводу приведенного примера. Во-первых, дополнительный набор круголых  скобочек в макросе проверки необходим, чтобы не  допустить интерпретации запятой внутри шаблона is_convertible   как разделителя аргументов макроса. Во-вторых, целевой тип для шаблона  &lt;a href="../../type_traits/ru/index.shtml"&gt;is_convertible&lt;/a&gt; является  ссылочным типом, так как некоторые компиляторы имеют  проблемы при использовании шаблона is_convertible, когда преобразование выполняется через определенный пользователем  конструктор; в любом случае не существует гарантий,  что классы свойств итераторов (iterator tag classes) могут конструироваться копированием (copy-constructible).&lt;/p&gt;&lt;p &gt;&lt;a name="class"&gt;&lt;/a&gt;Использование в области видимости класса&lt;/p&gt;&lt;p &gt;макрос обычно используется внутри шаблонных классов.  Предположим, что у нас есть шаблонный класс, для которого необходим беззнаковый целый тип с по крайней мере  16 битам в качестве параметра шаблона. Мы можем  проверять такое условие таким, к примеру,  образом:&lt;/p&gt;&lt;pre&gt;##include &amp;lt;climits&amp;gt;
#include &amp;lt;boost/static_assert.hpp&amp;gt;

template &amp;lt;class UnsignedInt&amp;gt;
class myclass
{
private:
   BOOST_STATIC_ASSERT(sizeof(UnsignedInt) * CHAR_BIT &amp;gt;= 16);
   BOOST_STATIC_ASSERT(std::numeric_limits&amp;lt;UnsignedInt&amp;gt;::is_specialized
                        &amp;amp;&amp;amp; std::numeric_limits&amp;lt;UnsignedInt&amp;gt;::is_integer
                        &amp;amp;&amp;amp; !std::numeric_limits&amp;lt;UnsignedInt&amp;gt;::is_signed);
public:
   /* details here */
};

&lt;/pre&gt;&lt;p &gt;Как это работает&lt;/p&gt;&lt;p&gt;BOOST_STATIC_ASSERT работает так.  Есть класс STATIC_ASSERTION_FAILURE, определенный так:&lt;/p&gt;&lt;pre&gt;namespace boost{

template &amp;lt;bool&amp;gt; struct STATIC_ASSERTION_FAILURE;

template &amp;lt;&amp;gt; struct STATIC_ASSERTION_FAILURE&amp;lt;true&amp;gt;{};

}&lt;/pre&gt;&lt;p &gt;Ключевой деталью является то,  что сообщение об ошибке включается посредством неопределенного выражения  sizeof(STATIC_ASSERTION_FAILURE&amp;lt;0&amp;gt;),  которое вроде бы правильно отрабатывает на большом множестве компиляторов.  Оставшаяся машинерия макроса BOOST_STATIC_ASSERT  это просто передача выражения sizeof в оператор  typedef. В данном случае использование макроса  является немного неуклюжим, однако разработчики  библиотека BOOST потратили значительные усилия в  попытках изобрести реализацию статических проверок без  макросов, и все безуспешно. В итоге было решено, что  выгода от правильной работы статической проверки в области видимости  пространства имен, функции и класса перевешивает  неуклюжесть макроса.&lt;/p&gt;&lt;p &gt;Тестовые программы&lt;/p&gt;&lt;p&gt;Следующие тестовые программы доступны в библиотеке:&lt;/p&gt;&lt;table border="1" width="100%" bordercolorlight="#808080" bordercolordark="#808080" style="border-collapse: collapse" cellpadding="5"&gt;&lt;tr&gt;         &lt;th width="33%"&gt;Тестовая программа&lt;/th&gt;         &lt;th width="33%"&gt;Компилируется ли&lt;/th&gt;         &lt;th width="34%"&gt;Описание&lt;/th&gt;     &lt;/tr&gt;
&lt;tr&gt;         &lt;td width="33%"&gt;static_assert_test.cpp&lt;/td&gt;         &lt;td width="33%"&gt;Да&lt;/td&gt;         &lt;td width="34%"&gt;Иллюстрирует использование.    Должна всегда успешно компилироваться, в    действительности проверяет совместимость компилятора.&lt;/td&gt;      &lt;/tr&gt;
&lt;tr&gt;         &lt;td width="33%"&gt;static_assert_example_1.cpp&lt;/td&gt;         &lt;td width="33%"&gt;Зависит от платформы.&lt;/td&gt;         &lt;td width="34%"&gt;Тестовая программа для использования в области видимости    пространства имен. Может успешно    компилироваться на некоторых платформах.&lt;/td&gt;     &lt;/tr&gt;
&lt;tr&gt;         &lt;td width="33%"&gt;static_assert_example_2.cpp&lt;/td&gt;         &lt;td width="33%"&gt;Да&lt;/td&gt;         &lt;td width="34%"&gt;Тестовая программа для области видимости функции.&lt;/td&gt;     &lt;/tr&gt;
&lt;tr&gt;         &lt;td width="33%" height="30"&gt;static_assert_example_3.cpp&lt;/td&gt;          &lt;td width="33%" height="30"&gt;Да&lt;/td&gt;         &lt;td width="34%" height="30"&gt;Тестовая программа для области видимости    класса.&lt;/td&gt;     &lt;/tr&gt;
&lt;tr&gt;         &lt;td width="33%"&gt;static_assert_test_fail_1.cpp&lt;/td&gt;         &lt;td width="33%"&gt;Нет&lt;/td&gt;         &lt;td width="34%"&gt;Пример генерации ошибки в области видимости пространства    имен.&lt;/td&gt;      &lt;/tr&gt;
&lt;tr&gt;         &lt;td width="33%"&gt;static_assert_test_fail_2.cpp&lt;/td&gt;         &lt;td width="33%"&gt;Нет&lt;/td&gt;         &lt;td width="34%"&gt;Пример генерации ошибки в области видимости не-шаблонной    функции.&lt;/td&gt;     &lt;/tr&gt;
&lt;tr&gt;          &lt;td width="33%"&gt;static_assert_test_fail_3.cpp&lt;/td&gt;         &lt;td width="33%"&gt;Нет&lt;/td&gt;         &lt;td width="34%"&gt;Пример генерации ошибки в области видимости    не-шаблонного класса.&lt;/td&gt;     &lt;/tr&gt;
&lt;tr&gt;         &lt;td width="33%"&gt;static_assert_test_fail_4.cpp&lt;/td&gt;         &lt;td width="33%"&gt;Нет&lt;/td&gt;          &lt;td width="34%"&gt;Пример генерации ошибки в области видимости    не-шаблонного класса.&lt;/td&gt;     &lt;/tr&gt;
&lt;tr&gt;         &lt;td width="33%"&gt;static_assert_test_fail_5.cpp&lt;/td&gt;         &lt;td width="33%"&gt;Нет&lt;/td&gt;         &lt;td width="34%"&gt;Пример генерации ошибки в области видимости шаблонного    класса.&lt;/td&gt;     &lt;/tr&gt;
&lt;tr&gt;         &lt;td width="33%"&gt;static_assert_test_fail_6.cpp&lt;/td&gt;         &lt;td width="33%"&gt;Нет&lt;/td&gt;         &lt;td width="34%"&gt;Пример генерации ошибки в области видимости метода    шаблонного класса.&lt;/td&gt;     &lt;/tr&gt;
&lt;tr&gt;         &lt;td width="33%"&gt;static_assert_test_fail_7.cpp&lt;/td&gt;          &lt;td width="33%"&gt;Нет&lt;/td&gt;         &lt;td width="34%"&gt;Пример генерации ошибки в области видимости класса.&lt;/td&gt;     &lt;/tr&gt;
&lt;tr&gt;         &lt;td&gt;static_assert_test_fail_8.cpp&lt;/td&gt;         &lt;td&gt;Нет&lt;/td&gt;         &lt;td&gt;Пример генерации ошибки в области видимости функции.&lt;/td&gt;      &lt;/tr&gt;
&lt;tr&gt;         &lt;td&gt;static_assert_test_fail_9.cpp&lt;/td&gt;         &lt;td&gt;Нет&lt;/td&gt;         &lt;td&gt;Пример генерации ошибки в области видимости функции (часть 2).&lt;/td&gt;     &lt;/tr&gt;
&lt;/table&gt;&lt;hr color="#C0C0C0" size="1"&gt; &lt;p&gt;P.S.: Нагло спёрто отсюда: &lt;a href="http://www.solarix.ru/for_developers/cpp/boost/static_assert/ru/static_assert.shtml"&gt;BOOST C++: проверки на стадии компиляции (static assertions)&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1252038906587337119-2600091652917654673?l=rakafon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rakafon.blogspot.com/feeds/2600091652917654673/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://rakafon.blogspot.com/2009/04/booststaticassert.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/2600091652917654673'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/2600091652917654673'/><link rel='alternate' type='text/html' href='http://rakafon.blogspot.com/2009/04/booststaticassert.html' title='Использование boost::static_assert'/><author><name>Rakafon</name><uri>http://www.blogger.com/profile/03386514126069055282</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-wnns05XIxW4/Ti7XTMmujOI/AAAAAAAAABg/rZpn54sM7BI/s1600/20168127'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1252038906587337119.post-6508600310781859274</id><published>2009-04-01T20:20:00.001+03:00</published><updated>2010-10-15T14:37:11.984+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='boost'/><category scheme='http://www.blogger.com/atom/ns#' term='cpp'/><title type='text'>Использование boos::call_traits</title><content type='html'>&lt;p&gt;Все содержимое &amp;lt;boost/call_traits.hpp&amp;gt;  объявлено в пространстве имен boost.&lt;/p&gt;&lt;p &gt;Шаблонный класс call_traits&amp;lt;T&amp;gt;  инкапсулирует &amp;quot;наилучший&amp;quot;   метод передачи параметра определенного типа T в  или из функции, и состоит из собрания операторов typedef, определенных  как показано в нижеследующей таблице. Предназначение call_traits  заключается в создании гарантий, что проблемы типа &amp;quot;&lt;a href="#refs"&gt;ссылка  на ссылку&lt;/a&gt;&amp;quot; не возникнут,  и что параметры передаются наиболее эффективным допустимым способом (см.  &lt;a href="#examples"&gt;примеры&lt;/a&gt;). &lt;/p&gt;&lt;p &gt;Заметьте, что для компиляторов, которые не поддерживают частичную специализацию или шаблоны-члены, использование шаблона call_traits не принесет никаких выгод. Дополнительно к  этому, если компилятор поддерживает шаблоны-члены и не  поддерживает частичную специализацию (Visual C++ 6),  тогда call_traits не может быть  использован с типами массивов (хотя он может быть использован для решения  проблемы &lt;i&gt;ссылка на ссылку&lt;/i&gt;).&lt;/p&gt;&lt;table border="1" cellpadding="7" cellspacing="1" width="100%" bordercolorlight="#808080" bordercolordark="#808080" style="border-collapse: collapse"&gt;&lt;tr&gt;         &lt;td valign="top" width="17%" bgcolor="#008080"&gt;&lt;p
        align="center"&gt;существующая практика&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="35%" bgcolor="#008080"&gt;&lt;p
        align="center"&gt;эквивалент с call_traits&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="32%" bgcolor="#008080"&gt;&lt;p
        align="center"&gt;описание&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="16%" bgcolor="#008080"&gt;&lt;p
        align="center"&gt;замечания&lt;/p&gt;&lt;/td&gt;     &lt;/tr&gt;
&lt;tr&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;T&lt;br /&gt;
(возвращается сама величина)&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="35%"&gt;&lt;p align="center"&gt;&lt;code&gt;   call_traits&amp;lt;T&amp;gt;::value_type&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="32%"&gt;Определяет тип,     который представляет &amp;quot;значение&amp;quot;    типа T. Используйте для функций, которые    возвращают значение, а также для хранения    величин типа T.&lt;/td&gt;         &lt;td valign="top" width="16%"&gt;&lt;p align="center"&gt;2&lt;/p&gt;&lt;/td&gt;     &lt;/tr&gt;
&lt;tr&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;T&amp;amp;&lt;br /&gt;
(возврат по значению)&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="35%"&gt;&lt;p align="center"&gt;&lt;code&gt;   call_traits&amp;lt;T&amp;gt;::reference&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="32%"&gt;Определяет тип,    представляющий ссылку на тип&amp;nbsp; T.    Используйте для функций,    которые должны возвращать T&amp;amp;.&lt;/td&gt;         &lt;td valign="top" width="16%"&gt;&lt;p align="center"&gt;1&lt;/p&gt;&lt;/td&gt;     &lt;/tr&gt;
&lt;tr&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;const T&amp;amp;&lt;br /&gt;
(возврат по значению)&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="35%"&gt;&lt;p align="center"&gt;&lt;code&gt;   call_traits&amp;lt;T&amp;gt;::const_reference&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="32%"&gt;Определяет тип,   представляющий константную ссылку на тип T.    Используйте для функций,    которые должны возвращать const T&amp;amp;.&lt;/td&gt;         &lt;td valign="top" width="16%"&gt;&lt;p align="center"&gt;1&lt;/p&gt;&lt;/td&gt;     &lt;/tr&gt;
&lt;tr&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;const T&amp;amp;&lt;br /&gt;
(параметр функции)&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="35%"&gt;&lt;p align="center"&gt;&lt;code&gt;   call_traits&amp;lt;T&amp;gt;::param_type&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="32%"&gt;Определяет тип,    который представляет &amp;quot;наилучший&amp;quot;    способ передавать параметр типа T в    функцию.&lt;/td&gt;         &lt;td valign="top" width="16%"&gt;&lt;p align="center"&gt;1,333&lt;/p&gt;&lt;/td&gt;      &lt;/tr&gt;
&lt;/table&gt;&lt;p&gt;Внимание:&lt;/p&gt;&lt;p &gt;Если T уже является типом  ссылки, тогда call_traits определяется таким  способом, что проблема &lt;a href="#refs"&gt;ссылка на  ссылку&lt;/a&gt; не возникает (требуется поддержка компилятором частичной  специализации).&lt;/p&gt;&lt;p &gt;Если T является типом  массива, тогда call_traits  определяет &lt;code&gt;value_type&lt;/code&gt; как &amp;quot;&lt;i&gt;константный  указатель на тип&lt;/i&gt;&amp;quot; вместо &amp;quot;&lt;i&gt;массива типов&lt;/i&gt;&amp;quot; (требуется  частичная специализация). Обратите внимание, что если  Вы используете value_type для хранения значения,  то это приведет к хранению &amp;quot;&lt;i&gt;константного указателя на массив&lt;/i&gt;&amp;quot;   вместо хранения самого массива. Это может быть хорошим или плохим решением в  зависимости от конкретной ситуации.&lt;/p&gt;&lt;p &gt;Если T это небольшой по  размеру встроенный тип или указатель, тогда &lt;code&gt;param_type&lt;/code&gt;  определяется как &lt;code&gt;T const&lt;/code&gt;, вместо &lt;code&gt;T const&amp;amp;&lt;/code&gt;.   Это может улучшить шансы компилятора на оптимизацию циклов в теле функции,  если они зависят от передаваемого параметра. В  остальных случаях сематника передаваемого параметра остается неизменной. Для  реализации этой возможности необходима частичная специализация.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p &gt;Возможность создания копированием&lt;/p&gt;&lt;p &gt;Следующая таблица определяет,  какие типы в шаблоне call_traits всегда могут  создаваться копированием из других типов. Случаи,  отмеченные '?', справедливы только если T можно конструировать  копированием:&lt;/p&gt;&lt;table border="1" cellpadding="7" cellspacing="1" width="766" bordercolorlight="#808080" bordercolordark="#808080" style="border-collapse: collapse"&gt;&lt;tr&gt;         &lt;td valign="top" width="17%"&gt;&amp;nbsp;&lt;/td&gt;         &lt;td valign="top" colspan="5" width="85%"
        bgcolor="#008080"&gt;&lt;p align="center"&gt;В:&lt;/p&gt;&lt;/td&gt;      &lt;/tr&gt;
&lt;tr&gt;         &lt;td valign="top" width="17%" bgcolor="#008080"&gt;Из:&lt;/td&gt;         &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;&lt;p
        align="center"&gt;T&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;&lt;p
        align="center"&gt;value_type&lt;/p&gt;&lt;/td&gt;          &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;&lt;p
        align="center"&gt;reference&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;&lt;p
        align="center"&gt;const_reference&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;&lt;p
        align="center"&gt;param_type&lt;/p&gt;&lt;/td&gt;     &lt;/tr&gt;
&lt;tr&gt;         &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;T&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;?&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;?&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;Y&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;Y&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;Y&lt;/p&gt;&lt;/td&gt;     &lt;/tr&gt;
&lt;tr&gt;         &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;value_type&lt;/td&gt;          &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;?&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;?&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;N&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;N&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;Y&lt;/p&gt;&lt;/td&gt;     &lt;/tr&gt;
&lt;tr&gt;         &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;reference&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;?&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;?&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;Y&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;Y&lt;/p&gt;&lt;/td&gt;          &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;Y&lt;/p&gt;&lt;/td&gt;     &lt;/tr&gt;
&lt;tr&gt;         &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;const_reference&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;?&lt;/p&gt;&lt;/td&gt;          &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;N&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;N&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;Y&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;Y&lt;/p&gt;&lt;/td&gt;     &lt;/tr&gt;
&lt;tr&gt;         &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;param_type&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;?&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;?&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;N&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;N&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;Y&lt;/p&gt;&lt;/td&gt;      &lt;/tr&gt;
&lt;/table&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Если T тип с работающим присваиванием, то следующие виды присваивания возможны:&lt;/p&gt;&lt;table border="1" cellpadding="7" cellspacing="1" width="766" bordercolorlight="#808080" bordercolordark="#808080" style="border-collapse: collapse"&gt;&lt;tr&gt;          &lt;td valign="top" width="17%"&gt;&amp;nbsp;&lt;/td&gt;         &lt;td valign="top" colspan="5" width="85%"
        bgcolor="#008080"&gt;&lt;p align="center"&gt;В:&lt;/p&gt;&lt;/td&gt;     &lt;/tr&gt;
&lt;tr&gt;         &lt;td valign="top" width="17%" bgcolor="#008080"&gt;Из:&lt;/td&gt;         &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;&lt;p
        align="center"&gt;T&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;&lt;p
        align="center"&gt;value_type&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;&lt;p
        align="center"&gt;reference&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;&lt;p
        align="center"&gt;const_reference&lt;/p&gt;&lt;/td&gt;          &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;&lt;p
        align="center"&gt;param_type&lt;/p&gt;&lt;/td&gt;     &lt;/tr&gt;
&lt;tr&gt;         &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;T&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;Y&lt;/p&gt;&lt;/td&gt;          &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;Y&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;-&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;-&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;-&lt;/p&gt;&lt;/td&gt;     &lt;/tr&gt;
&lt;tr&gt;         &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;value_type&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;Y&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;Y&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;--&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;-&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;-&lt;/p&gt;&lt;/td&gt;      &lt;/tr&gt;
&lt;tr&gt;         &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;reference&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;Y&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;Y&lt;/p&gt;&lt;/td&gt;          &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;-&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;-&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;-&lt;/p&gt;&lt;/td&gt;     &lt;/tr&gt;
&lt;tr&gt;         &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;const_reference&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;Y&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;Y&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;--&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;-&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;-&lt;/p&gt;&lt;/td&gt;     &lt;/tr&gt;
&lt;tr&gt;         &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;param_type&lt;/td&gt;          &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;Y&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;Y&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;--&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;-&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;-&lt;/p&gt;&lt;/td&gt;     &lt;/tr&gt;
&lt;/table&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p &gt;&lt;a name="examples"&gt;&lt;/a&gt;Примеры&lt;/p&gt;&lt;p &gt;Следующая таблица показывает эффект,  который получается применением call_traits  к различным типам. Подразумевается, что компилятор поддерживает частичную специализацию:  если это не так, то все типы ведут себя так же, как в графе для &amp;quot;myclass&amp;quot;, и call_traits   не может быть использован со ссылками или типами массивов.&lt;/p&gt;&lt;table border="1" cellpadding="2" cellspacing="0" width="766" bordercolorlight="#808080" bordercolordark="#808080" style="border-collapse: collapse"&gt;&lt;tr&gt;         &lt;td valign="top" width="17%"&gt;&amp;nbsp;&lt;/td&gt;         &lt;td valign="top" colspan="5" width="85%"
        bgcolor="#008080"&gt;&lt;p align="center"&gt;тип-результат &lt;b&gt;   call_traits&lt;/b&gt;:&lt;/p&gt;&lt;/td&gt;      &lt;/tr&gt;
&lt;tr&gt;         &lt;td valign="top" width="17%" bgcolor="#008080"&gt;&lt;p
        align="center"&gt;исходный тип T&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;&lt;p
        align="center"&gt;value_type&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;&lt;p
        align="center"&gt;reference&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;&lt;p
        align="center"&gt;const_reference&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;&lt;p
        align="center"&gt;param_type&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;&lt;p
        align="center"&gt;может применяться для:&lt;/p&gt;&lt;/td&gt;      &lt;/tr&gt;
&lt;tr&gt;         &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;&lt;p
        align="center"&gt;myclass&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;myclass&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;myclass&amp;amp;&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;const myclass&amp;amp;&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;myclass const&amp;amp;&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;всех определенных    пользователем типов.&lt;/p&gt;&lt;/td&gt;      &lt;/tr&gt;
&lt;tr&gt;         &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;&lt;p
        align="center"&gt;int&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;int&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;int&amp;amp;&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;const int&amp;amp;&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;int const&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;всех небольших встроенных    типов.&lt;/p&gt;&lt;/td&gt;      &lt;/tr&gt;
&lt;tr&gt;         &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;&lt;p
        align="center"&gt;int*&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;int*&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;int*&amp;amp;&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;int*const&amp;amp;&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;int* const&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;любых указателей.&lt;/p&gt;&lt;/td&gt;      &lt;/tr&gt;
&lt;tr&gt;         &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;&lt;p
        align="center"&gt;int&amp;amp;&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;int&amp;amp;&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;int&amp;amp;&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;const int&amp;amp;&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;int&amp;amp;&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;любых ссылок.&lt;/p&gt;&lt;/td&gt;      &lt;/tr&gt;
&lt;tr&gt;         &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;&lt;p
        align="center"&gt;const int&amp;amp;&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;const int&amp;amp;&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;const int&amp;amp;&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;const int&amp;amp;&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;const int&amp;amp;&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;всех константных ссылок.&lt;/p&gt;&lt;/td&gt;      &lt;/tr&gt;
&lt;tr&gt;         &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;&lt;p
        align="center"&gt;int[3]&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;const int*&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;int(&amp;amp;)[3]&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;const int(&amp;amp;)[3]&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;const int* const&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;всех типов маккисов.&lt;/p&gt;&lt;/td&gt;      &lt;/tr&gt;
&lt;tr&gt;         &lt;td valign="top" width="17%" bgcolor="#C0C0C0"&gt;&lt;p
        align="center"&gt;const int[3]&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;const int*&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;const int(&amp;amp;)[3]&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;const int(&amp;amp;)[3]&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;const int* const&lt;/p&gt;&lt;/td&gt;         &lt;td valign="top" width="17%"&gt;&lt;p align="center"&gt;всех константных массивов.&lt;/p&gt;&lt;/td&gt;      &lt;/tr&gt;
&lt;/table&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p &gt;Пример 1:&lt;/p&gt;&lt;p &gt;Следующий класс является простейшим случаем, он хранит величину типа T (см. файл call_traits_test.cpp). Демонстрируется, как можно использовать все  возможные типы в call_traits:&lt;/p&gt;&lt;pre&gt;template &amp;lt;class T&amp;gt;
struct contained
{
   // define our typedefs first, arrays are stored by value
   // so value_type is not the same as result_type:
   typedef typename boost::call_traits&amp;lt;T&amp;gt;::param_type       param_type;
   typedef typename boost::call_traits&amp;lt;T&amp;gt;::reference        reference;
   typedef typename boost::call_traits&amp;lt;T&amp;gt;::const_reference  const_reference;
   typedef T                                                value_type;
   typedef typename boost::call_traits&amp;lt;T&amp;gt;::value_type       result_type;

   // stored value:
   value_type v_;
   
   // constructors:
   contained() {}
   contained(param_type p) : v_(p){}
   // return byval:
   result_type value() { return v_; }
   // return by_ref:
   reference get() { return v_; }
   const_reference const_get()const { return v_; }
   // pass value:
   void call(param_type p){}

};&lt;/pre&gt;&lt;p &gt;&lt;a name="refs"&gt;&lt;/a&gt;Пример 2 (проблема ссылки на ссылку):&lt;/p&gt;&lt;p&gt;Рассмотрим определение std::binder1st:&lt;/p&gt;&lt;pre&gt;template &amp;lt;class Operation&amp;gt; 
class binder1st : 
   public unary_function&amp;lt;typename Operation::second_argument_type, typename Operation::result_type&amp;gt; 
{ 
protected: 
   Operation op; 
   typename Operation::first_argument_type value; 
public: 
   binder1st(const Operation&amp;amp; x, const typename Operation::first_argument_type&amp;amp; y); 
   typename Operation::result_type operator()(const typename Operation::second_argument_type&amp;amp; x) const; 
}; &lt;/pre&gt;&lt;p &gt;Теперь посмотрим, что будет в  относительно общем случае, когда функтор получает свой  второй аргумент как ссылку, что подразумевает, что &lt;code&gt; Operation::second_argument_type&lt;/code&gt; является типом ссылки, &lt;code&gt;operator()&lt;/code&gt;  теперь определяется как получающий ссылку на ссылку,   что некорректно для текущего стандарта C++. Решение  заключается в том, чтобы модифицировать определение operator() с использованием call_traits:&lt;/p&gt;&lt;pre&gt;typename Operation::result_type operator()(typename call_traits&amp;lt;typename Operation::second_argument_type&amp;gt;::param_type x) const;&lt;/pre&gt;&lt;p &gt;Теперь в случае, если &lt;code&gt;Operation::second_argument_type&lt;/code&gt; является типом ссылки, аргумент передается как ссылка, и проблема &amp;quot;ссылка на ссылку&amp;quot; не  возникает.&lt;/p&gt;&lt;p &gt;&lt;a name="ex3"&gt;&lt;/a&gt;Пример 3 (проблема с make_pair):&lt;/p&gt;&lt;p &gt;Если мы передает имя массива как один (или оба) аргумента  в &lt;code&gt;  std::make_pair&lt;/code&gt;, тогда алгоритм вывода аргументов шаблона воспринимает  преданный параметр как &amp;quot;константная ссылка на массив типов T&amp;quot;, это  также применимо к строковым литералам (которые на самом деле также являются  массивами). Следовательно вместо возврата пары указателей, происходит возврат пары массивов, а так как тип массивов не может  создаваться копированием, то код не компилируется.  Одним решением может быть явное преобразование аргументов make_pair к указателям, но call_traits дает лучшее (т.е. автоматическое)  решение (которое безопасно в обобщенном коде, где  преобразования могут привести к неверному результату):&lt;/p&gt;&lt;pre&gt;template &amp;lt;class T1, class T2&amp;gt;
std::pair&amp;lt;
   typename boost::call_traits&amp;lt;T1&amp;gt;::value_type, 
   typename boost::call_traits&amp;lt;T2&amp;gt;::value_type&amp;gt; 
      make_pair(const T1&amp;amp; t1, const T2&amp;amp; t2)
{
   return std::pair&amp;lt;

      typename boost::call_traits&amp;lt;T1&amp;gt;::value_type, 
      typename boost::call_traits&amp;lt;T2&amp;gt;::value_type&amp;gt;(t1, t2);
}&lt;/pre&gt;&lt;p &gt;Здесь полученные при выводе типы аргументов будут  автоматически усечены до указателей, если выведенные  типы являются массивами. Аналогичная ситуация  возникает со стандартными байндерами и адаптерами (binders and adapters): в  принципе, это справедливо для любой функции,  которая &amp;quot;обертывает&amp;quot;  временный объект, чей тип выводится. Обратите внимание, аргументы функции для make_pair не  выражаются в терминах call_traits: это могло бы  привести к невозможности вывести аргументы шаблона.&lt;/p&gt;&lt;p &gt;&lt;a name="ex4"&gt;&lt;/a&gt;Пример 4 (оптимизация алгоритма  fill):&lt;/p&gt;&lt;p &gt;Шаблон call_traits может &amp;quot;оптимизировать&amp;quot; передачу  небольших встроенных встроенных типов как аргументов функции. В следующем  примере (см. fill_example.cpp), версия std::fill оптимизируется двумя способами: если  передаваемый тип является встроенным однобайтовым типом,  то используется std::memset, иначе используется обычная реализация алгоритма копирования, но с применением &amp;quot;оптимизации&amp;quot; передачи параметров через call_traits:&lt;/p&gt;&lt;pre&gt;namespace detail{

template &amp;lt;bool opt&amp;gt;
struct filler
{{
   template &amp;lt;typename I, typename T&amp;gt;

   static void do_fill(I first, I last, typename boost::call_traits&amp;lt;T&amp;gt;::param_type val);
   {
      while(first != last)
      {
         *first = val;
         ++first;
      }
   }
};

template &amp;lt;&amp;gt;
struct filler&amp;lt;true&amp;gt;
{
   template &amp;lt;typename I, typename T&amp;gt;
   static void do_fill(I first, I last, T val)
   {
      memset(first, val, last-first);
   }
};

}

template &amp;lt;class I, class T&amp;gt;
inline void fill(I first, I last, const T&amp;amp; val)
{
   enum{ can_opt = boost::is_pointer&amp;lt;I&amp;gt;::value
                   &amp;amp;&amp;amp; boost::is_arithmetic&amp;lt;T&amp;gt;::value
                   &amp;amp;&amp;amp; (sizeof(T) == 1) };
   typedef detail::filler&amp;lt;can_opt&amp;gt; filler_t;
   filler_t::template do_fill&amp;lt;I,T&amp;gt;(first, last, val);}}&lt;/pre&gt;&lt;p &gt;Примечение: причина того, что &amp;quot;оптимальным&amp;quot;  небольших встроенных типов является передача как T const  вместо const T&amp;amp; заключается в том, что компилятор может определить, что величина  неизменна и для нее нет синонимов (aliases). С такой  информацией компилятор способен закэшировать передаваемое значение в регистре,  развернуть (unroll) цикл, или использовать параллельные инструкции.  Точнее говоря, эффект от применения такой оптимизации  зависит от компилятора.&lt;/p&gt;&lt;p &gt;Обратите внимание, аргументы функции для make_pair не  выражаются в терминах call_traits: это могло бы  привести к невозможности вывести аргументы шаблона. Вместо этого  fill работает как &amp;quot;тонкая обертка&amp;quot;, предназначенная для выполнения вывода аргументов шаблона. В любом случае компилятор соптимизирует вызов fill,  заменив его на вызов filler&amp;lt;&amp;gt;::do_fill,  который использует call_traits.&lt;/p&gt;&lt;p &gt;Обоснование&lt;/p&gt;&lt;p&gt;Следующие замечанию кратко описывают причины выбора решений в call_traits.&lt;/p&gt;&lt;p&gt;Все определенные пользователем типы следуют &amp;quot;существующей практике&amp;quot;  и не нуждаются в комментариях.&lt;/p&gt;&lt;p &gt;Небольшие встроенные типы (то,   что стандарт называет фундаментальными типами [3.9.1])  отличаются от существующей практики только реализацией  call_traits&amp;lt;&amp;gt;::param_type. В этом случае  передача &amp;quot;T const&amp;quot; совместима с  существующей практикой,  но может улучшить эффективность в некоторых случаях (см. &lt;a href="#ex4"&gt;Пример 4&lt;/a&gt;),  в любом случае это не должно быть хуже, чем  существующая практика.&lt;/p&gt;&lt;p&gt;Указатели ведут себя как небольшие встроенные типы.&lt;/p&gt;&lt;p &gt;Для ссылочных типов реализация следует &lt;a href="#refs"&gt;примеру 2&lt;/a&gt; -  ссылки на ссылки не допускаются, так что call_traits  предотвращает возникновение этой проблемы. Есть предложение изменить C++ таким образом, чтобы  ссылка на ссылку была эквивалентна одной ссылке (предложение #106,  сделано Bjarne Stroustrup), call_traits&amp;lt;T&amp;gt;::value_type  и  call_traits&amp;lt;T&amp;gt;::param_type обеспечивают  этот же предложенный эффект, без необходимости менять  язык.&lt;/p&gt;&lt;p &gt;Для типов массивов, функция,  которая получает массив как аргумент, усекает его до  указателя: это ознчает, что  тип действительного параметра отличается от объявленного типа.  Иногда это может вызвать проблемы в коде шаблона, который опирается на объявленный тип параметра.  К примеру:&lt;/p&gt;&lt;pre&gt;template &amp;lt;class T&amp;gt;
struct A
{
   void foo(T t);
};&lt;/pre&gt;&lt;p &gt;В данном случае если мы конкретизируем A&amp;lt;int[2]&amp;gt;, тогда  объявленный тип параметра, передаваемого в  функцию-метод foo будет  int[2], но действительный тип будет const int*. Если мы  попытаемся использовать тип T внутри тела  функции, тогда есть большая вероятность, что наш код не скомпилируется:&lt;/p&gt;&lt;pre&gt;template &amp;lt;class T&amp;gt;

void A&amp;lt;T&amp;gt;::foo(T t)
{
   T dup(t); // doesn't compile for case that T is an array.
}&lt;/pre&gt;&lt;p&gt;При использовании call_traits усечение  массива к указателю является явным, и тип параметра тот же самый, что объявленный тип:&lt;/p&gt;&lt;pre&gt;template &amp;lt;class T&amp;gt;
struct A
{
   void foo(typename call_traits&amp;lt;T&amp;gt;::value_type t);
};

template &amp;lt;class T&amp;gt;

void A&amp;lt;T&amp;gt;::foo(typename call_traits&amp;lt;T&amp;gt;::value_type t)
{
   typename call_traits&amp;lt;T&amp;gt;::value_type dup(t); // OK even if T is an array type.
}&lt;/pre&gt;&lt;p &gt;Для value_type (возврат  по значению) опять-таки только массив может быть возвращен,  а не целый массив, и снова  call_traits делает усечени явным.  Член value_type полезен в любом случае, когда массив должен быть явно усечен до указателя - &lt;a
href="#ex3"&gt;пример 3&lt;/a&gt; показывает тестовый случай (примечание:  специализация с массивом для call_traits  наименее понятна из всех специализаций call_traits;  если данная семантика вызывает у Вас какие-то трудности, или не решает какую-то проблему с массивами,  тогда я буду рад услышать об этом. Большинству разработчиков данная  специализация не нужна).&lt;/p&gt;&lt;p&gt;P.S.: Нагло спёрто отсюда: &lt;a href="http://www.solarix.ru/for_developers/cpp/boost/utility/ru/call_traits.shtml"&gt;BOOST C++: заголовочный файл &amp;lt;boost/call_traits.hpp&amp;gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1252038906587337119-6508600310781859274?l=rakafon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rakafon.blogspot.com/feeds/6508600310781859274/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://rakafon.blogspot.com/2009/04/booscalltraits.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/6508600310781859274'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/6508600310781859274'/><link rel='alternate' type='text/html' href='http://rakafon.blogspot.com/2009/04/booscalltraits.html' title='Использование boos::call_traits'/><author><name>Rakafon</name><uri>http://www.blogger.com/profile/03386514126069055282</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-wnns05XIxW4/Ti7XTMmujOI/AAAAAAAAABg/rZpn54sM7BI/s1600/20168127'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1252038906587337119.post-8247907929065127998</id><published>2009-04-01T20:00:00.001+03:00</published><updated>2010-10-15T14:37:16.727+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='boost'/><category scheme='http://www.blogger.com/atom/ns#' term='cpp'/><title type='text'>Использование идиомы boost::base_from_member</title><content type='html'>&lt;p&gt;Шаблон класса &lt;code&gt;boost::base_from_member&lt;/code&gt;  предоставляет возможность создавать классы, которые  выполняют инициализацию своего базового класса членом класса. Шаблон класса находится в boost/utility/base_from_member.hpp,  который включается в boost/utility.hpp. Предварительное (forward) объявление шаблона класса  находится в boost/utility_fwd.hpp.&lt;/p&gt;&lt;p&gt;Пример использования - в файле base_from_member_test.cpp.&lt;/p&gt;&lt;p&gt;&lt;a name="contents"&gt;&lt;/a&gt;Содержание&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;a href="#rationale"&gt;Обоснование&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="#synopsis"&gt;Краткое описание&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="#usage"&gt;Использование&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="#example"&gt;Пример&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;a name="rationale"&gt;&lt;/a&gt;Обоснование&lt;/p&gt;&lt;p&gt;При разработке класса иногда возникает необходимость инициализировать базовый  класс членом текущего класса. Простой пример:&lt;/p&gt;&lt;blockquote&gt;&lt;pre&gt;#include &amp;lt;streambuf&amp;gt;  &lt;i&gt;// for std::streambuf&lt;/i&gt;
#include &amp;lt;ostream&amp;gt;    &lt;i&gt;// for std::ostream&lt;/i&gt;

class fdoutbuf
    : public std::streambuf
{
public:
    explicit fdoutbuf( int fd );
    //...
};

class fdostream
    : public std::ostream
{
protected:
    fdoutbuf buf;
public:
    explicit fdostream( int fd )
        : buf( fd ), std::ostream( &amp;amp;buf )
        {}  {}
    //.};
&lt;/pre&gt;&lt;/blockquote&gt;&lt;p&gt;Поведение кода неопределено,  так как порядок инициализации в C++ обязывает  компилятор инициализировать базовый класс прежде, чем  инициализировать члены класса.  &lt;a href="http://www.moocat.org"&gt;R. Samuel Klatchko&lt;/a&gt; разработал обходной маневр с надлежащим использованием порядка инициализации.   Базовые классы инициализируются в порядке объявления, так что перемещение необходимого члена в другой базовый класс, который объявлен базовым перед другим базовым классом, позволяет гарантировать надлежащую инициализацию.&lt;/p&gt;&lt;p&gt;Собственный базовый класс может быть сделан из идиомы:&lt;/p&gt;&lt;blockquote&gt;&lt;pre&gt;#include &amp;lt;streambuf&amp;gt;  &lt;i&gt;// for std::streambuf&lt;/i&gt;

#include &amp;lt;ostream&amp;gt;    &lt;i&gt;// for std::ostream&lt;/i&gt;

class fdoutbuf
    : public std::streambuf
{
public:
    explicit fdoutbuf( int fd );
    //.../...
};

struct fdostream_pbase
{
    fdoutbuf sbuffer;

    explicit fdostream_pbase( int fd )
        : sbuffer( fd )
        {}
};

class fdostream
    : private fdostream_pbase
    , public std::ostream
{
    typedef fdostream_pbase  pbase_type;
    typedef std::ostream     base_type;

public:
    explicit fdostream( int fd )
        : pbase_type( fd ), base_type( &amp;amp;sbuffer )
        {}
    //...
};
&lt;/pre&gt;&lt;/blockquote&gt;&lt;p&gt;Другие проекты могут использовать похожие  пользовательские базовые классы.  Технология достаточно общая, чтобы создать шаблонный класс в данной библиотеке.  Главный параметр  шаблона имеет тип включенного члена класса. Шаблонный  класс имеет несколько (явных) шаблонов конструктора,   которые неявно определяют тип аргументов конструктора и передают их члену класса.  Шаблонный класс имеет неявные конструктор копирования и оператор присваивания, что позволяет им отключаться, если включаемый  член является некопируемым.&lt;/p&gt;&lt;p&gt;Manually coding a base class may be better if the construction and/or copying needs are too complex for the supplied template class, or if the compiler is not advanced enough to use it.&lt;/p&gt;&lt;p&gt;Since base classes are unnamed, a class cannot have multiple (direct) base classes of the same type.  The supplied template class has an extra template parameter, an integer, that exists solely to provide type differentiation.  This parameter has a default value so a single use of a particular member type does not need to concern itself with the integer.&lt;/p&gt;&lt;p&gt;&lt;a name="synopsis"&gt;&lt;/a&gt;Краткое описание&lt;/p&gt;&lt;blockquote&gt;&lt;pre&gt;template &amp;lt; typename MemberType, int UniqueID = 0 &amp;gt;
class boost::base_from_member
{
protected:
    MemberType  member;

    base_from_member();

    template&amp;lt; typename T1 &amp;gt;
    explicit  base_from_member( T1 x1 );

    template&amp;lt; typename T1, typename T2 &amp;gt;

    base_from_member( T1 x1, T2 x2 );

    //...

    template&amp;lt; typename T1, typename T2, typename T3, typename T4,
     typename T5, typename T6, typename T7, typename T8, typename T9,
     typename T10 &amp;gt;
    base_from_member( T1 x1, T2 x2, T3 x3, T4 x4, T5 x5, T6 x6, T7 x7,
     T8 x8, T9 x9, T10 x10 );
};
&lt;/pre&gt;&lt;/blockquote&gt;&lt;p&gt;Первый аргумент шаблонного класса &lt;var&gt;MemberType&lt;/var&gt; -  это тип члена в базовом классе (based-member). Последний аргумент шаблона &lt;var&gt;UniqueID&lt;/var&gt;, имеющий тип  &lt;code&gt;int&lt;/code&gt;, предназначен для введения различий между несколькими базовыми  классами, которые используют один и тот же&amp;nbsp; член  в базовом классе (based-member type).  Последний параметр шаблона имеет значение  по умолчанию 0.  Шаблонный класс имеет защищенное поле &lt;var&gt;member&lt;/var&gt;, которое производный класс может использовать для последующих базовых  классов (или для себя самого).&lt;/p&gt;&lt;p&gt;Имеется конструктор по умолчанию и несколько шаблонов  конструкторов. Эти шаблоны конструктора получают до 10  (в текущей версии) аргументов и передавать их в конструктор поля класса (data member).   Так как C++ в любом случае не позволяет явно указывать параметры шаблона  конструктора, следует убедиться, что аргументы  максимально похожи по типу на действительные типы,   используемые в соответствующем конструкторе поля класса.&lt;/p&gt;&lt;p&gt;&lt;a name="usage"&gt;&lt;/a&gt;Использование&lt;/p&gt;&lt;p&gt;В качестве начального примера можно рассмотреть  под-объект (sub-object) &lt;code&gt;fdoutbuf&lt;/code&gt;, который нужно заключить внутри базового класса,  от которого происходит наследование перед &lt;code&gt;std::ostream&lt;/code&gt;.&lt;/p&gt;&lt;blockquote&gt;&lt;pre&gt;#include &amp;lt;boost/utility/base_from_member.hpp&amp;gt;

#include &amp;lt;streambuf&amp;gt;  &lt;i&gt;// for std::streambuf&lt;/i&gt;
#include &amp;lt;ostream&amp;gt;    &lt;i&gt;// for std::ostream&lt;/i&gt;

class fdoutbuf
    : public std::streambuf
{
public:
    explicit fdoutbuf( int fd );
    //...
};

class fdostream
    : private boost::base_from_member&amp;lt;fdoutbuf&amp;gt;
    , public std::ostream
{
    // Helper typedef's
    typedef boost::base_from_member&amp;lt;fdoutbuf&amp;gt;  pbase_type;
    typedef std::ostream                        base_type;

public:
    explicit fdostream( int fd )
        : pbase_type( fd ), base_type( &amp;amp;member )
        {}
    //...
}; 
&lt;/pre&gt;&lt;/blockquote&gt;&lt;p&gt;Идиома base-from-member является деталью реализации, которая не должна быть видима пользователям класса класса &lt;code&gt;fdostream&lt;/code&gt;.  Из-за порядка инициализации,   под-объект &lt;code&gt;fdoutbuf&lt;/code&gt; инициализируется перед под-объектом &lt;code&gt;std::ostream&lt;/code&gt;,  что позволяет безопасно использовать последний под-объект в дальнейшем  конструировании под-объектов.  так как под-объект &lt;code&gt;fdoutbuf&lt;/code&gt;  конечного типа является единственным под-объектом с именем &amp;quot;member&amp;quot;,  это имя может быть пропущено (unqualified) внутри конечного класса.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;a name="example"&gt;&lt;/a&gt;Пример&lt;/p&gt;&lt;p&gt;Шаблоны классов, использующих  идиому base-from-member, типично используют  единственный под-объект base-from-member, обычно для  прикрепления буфера к потоку ввода вывода (a stream-buffer to an I/O stream).  Следующий пример демонстрирует, как использовать множественные под-объекты base-from-member, и показывает некоторые другие моменты,  связанные с именованием полей.&lt;/p&gt;&lt;blockquote&gt;&lt;pre&gt;#include &amp;lt;boost/utility/base_from_member.hpp&amp;gt;

#include &amp;lt;cstddef&amp;gt;  &lt;i&gt;// for NULL&lt;/i&gt;

struct an_int
{
    int  y;

    an_int( float yf );
};

class switcher
{
public:
    switcher();
    switcher( double, int * );
    //...
};

class flow_regulator
{
public:
    flow_regulator( switcher &amp;amp;, switcher &amp;amp; );
    //...
};

template &amp;lt; unsigned Size &amp;gt;

class fan
{
public:
    explicit fan( switcher );
    //...
};

class system
    : private boost::base_from_member&amp;lt;an_int&amp;gt;
    , private boost::base_from_member&amp;lt;switcher&amp;gt;
    , private boost::base_from_member&amp;lt;switcher, 1&amp;gt;
    , private boost::base_from_member&amp;lt;switcher, 2&amp;gt;
    , protected flow_regulator
    , public fan&amp;lt;6&amp;gt;

{
    // Helper typedef's
    typedef boost::base_from_member&amp;lt;an_int&amp;gt;       pbase0_type;
    typedef boost::base_from_member&amp;lt;switcher&amp;gt;     pbase1_type;
    typedef boost::base_from_member&amp;lt;switcher, 1&amp;gt;  pbase2_type;
    typedef boost::base_from_member&amp;lt;switcher, 2&amp;gt;  pbase3_type;

    typedef flow_regulator  base1_type;
    typedef fan&amp;lt;6&amp;gt;          base2_type;

public:
    system( double x );
    //...
};

system::system( double x )
    : pbase0_type( 0.2 )
    , pbase1_type()
    , pbase2_type( -16, &amp;amp;this-&amp;gt;pbase0_type::member )
    , pbase3_type( x, static_cast&amp;lt;int *&amp;gt;(NULL) )
    , base1_type( pbase3_type::member, pbase1_type::member )
    , base2_type( pbase2_type::member )
{
    //...
}

&lt;/pre&gt;&lt;/blockquote&gt;&lt;p&gt;Конечный класс имеет несколько подобъектов с именем &amp;quot;member,&amp;quot; поэтому любое использование этого имени должно  сопровождаться квалификацией именем соответствующего базового класса.  (Использование  оператора &lt;code&gt;typedef&lt;/code&gt; облегчает задачу).  Однако, данное решение создает новую проблему, когда необходим указатель. Использование  оператора взятия адреса с под-объектом,   квалифицированным именем своего класса, дает  указатель-на-член (pointer-to-member) (в данном случае, к типу &lt;code&gt;an_int boost::base_from_member&amp;lt;an_int, 0&amp;gt; :: *&lt;/code&gt;) вместо указателя на член (к типу &lt;code&gt;an_int *&lt;/code&gt;).   Новая проблема решается через квалифицирование под-объекта с &amp;quot;&lt;code&gt;this-&amp;gt;&lt;/code&gt;,&amp;quot;  и необходимо только для указателей, а не для ссылок  или значений.&lt;/p&gt;&lt;p&gt;При инициализации происходит несколько преобразований  аргументов.  Аргумент конструктора &lt;code&gt;pbase0_type&lt;/code&gt; преобразуется из &lt;code&gt;double&lt;/code&gt; в &lt;code&gt;float&lt;/code&gt;.  Первый аргумент конструктора для &lt;code&gt;pbase2_type&lt;/code&gt; преобразуется из &lt;code&gt;int&lt;/code&gt; в &lt;code&gt;double&lt;/code&gt;.   Второй аргумент конструктора для &lt;code&gt;pbase3_type&lt;/code&gt; - это особый случай  необходимого преобразования; все формы литерала для  нулевого указателя в C++ выглядят как целочисленная константа времени компиляции,  так что C++ всегда интерпретирует такой код как целое число в случаях, когда при перегрузке функций может  быть целое число или указатель.  Последнее преобразование необходимо для  компилятора при вызове конструктора с точно определенным типом указателя в  качестве аргумента при использовании в &lt;code&gt;switcher&lt;/code&gt;'s constructor.&lt;/p&gt;&lt;p&gt;P.S.: Нагло спёрто отсюда: &lt;a href="http://www.solarix.ru/for_developers/cpp/boost/utility/ru/base_from_member.shtml"&gt;BOOST C++: идиома Base-from-Member&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1252038906587337119-8247907929065127998?l=rakafon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rakafon.blogspot.com/feeds/8247907929065127998/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://rakafon.blogspot.com/2009/04/boostbasefrommember.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/8247907929065127998'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/8247907929065127998'/><link rel='alternate' type='text/html' href='http://rakafon.blogspot.com/2009/04/boostbasefrommember.html' title='Использование идиомы boost::base_from_member'/><author><name>Rakafon</name><uri>http://www.blogger.com/profile/03386514126069055282</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-wnns05XIxW4/Ti7XTMmujOI/AAAAAAAAABg/rZpn54sM7BI/s1600/20168127'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1252038906587337119.post-7171886092468429530</id><published>2009-04-01T19:40:00.001+03:00</published><updated>2010-10-15T14:37:23.199+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='boost'/><category scheme='http://www.blogger.com/atom/ns#' term='cpp'/><title type='text'>Использование boost::utility</title><content type='html'>&lt;p&gt;Все объявления в хидере         &amp;lt;boost/utility.hpp&amp;gt;             включены в пространство имен &lt;code&gt;boost&lt;/code&gt;.&lt;/p&gt;&lt;p &gt;Содержание&lt;/p&gt;&lt;ul&gt;&lt;li&gt;                 Шаблоны функций &lt;a href="#checked_delete"&gt;checked_delete()                  и checked_array_delete()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;                 Шаблоны функций &lt;a href="#functions_next_prior"&gt;next() and                  prior()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;                 Класс &lt;a href="#Class_noncopyable"&gt;noncopyable&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;                 Шаблоны функций &lt;a href="#addressof"&gt;addressof()&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;h3&gt;            Шаблоны функций &lt;a name="checked_delete"&gt;&lt;/a&gt;checked_delete() и checked_array_delete()&lt;/h3&gt;&lt;p &gt;   Заголовный файл &amp;lt;boost/checked_delete.hpp&amp;gt;     содержит определение двух шаблонов функций checked_delete     и     checked_array_delete, и два шаблона     классов:    checked_deleter и     checked_array_deleter.   &lt;/p&gt;&lt;p &gt;Стандарт C++ (в 5.3.5/5)    разрешает освобождать указатели на неполные типы через   delete. Когда    класс имеет непустой деструктор или определенный для класса оператор   delete, поведение такой операции становится    неопределенным. Некоторые компиляторы печатают    предупреждение, когда удаляется неполный тип,    но, к несчастью, это    делают не все компиляторы, а программисты    иногда игнорируют или блокируют предупреждения.&lt;/P&gt;&lt;p &gt;В частности, проблемным    случаем является использование деструктора в шаблоне умного указателя,   такого как boost::scoped_ptr&amp;lt;T&amp;gt;::~scoped_ptr,    для неполностью определенного типа. Это    зачастую приводит к трудно обнаруживаемым сбоям в работе программ.&lt;/P&gt;&lt;p&gt;Предлагаемая функция и шаблон класса могут быть использованы для    предотвращения этих проблем, потому что они    требуют передачи им полностью определенного типа,   и генерируют ошибку компиляции в противном случае.&lt;/P&gt;&lt;p &gt;&lt;a name="Synopsis"&gt;&lt;/a&gt;Краткое описание&lt;/p&gt;&lt;pre&gt;namespace boost
{
 template&amp;lt;class T&amp;gt; void checked_delete(T * p);
 template&amp;lt;class T&amp;gt; void checked_array_delete(T * p);
 template&amp;lt;class T&amp;gt; struct checked_deleter;

 template&amp;lt;class T&amp;gt; struct checked_array_deleter;
}
&lt;/pre&gt;&lt;p &gt;checked_delete&lt;/p&gt;&lt;p &gt;&lt;a name="checked_delete"&gt;&lt;/a&gt;template&amp;lt;class T&amp;gt; void checked_delete(T *p);&lt;/p&gt;&lt;p &gt;&lt;b&gt;Требует:&lt;/b&gt; &lt;b&gt;T&lt;/b&gt; должен быть полным типом    (complete type). Выражение &lt;tt&gt;delete p&lt;/tt&gt;      должно быть синтаксически верным. &lt;/p&gt;&lt;p &gt;&lt;b&gt;Эффекты:&lt;/b&gt; &lt;tt&gt;delete p;&lt;/tt&gt; &lt;/p&gt;&lt;p &gt;checked_array_delete&lt;/p&gt;&lt;p &gt;&lt;a name="checked_array_delete"&gt;&lt;/A&gt;template&amp;lt;class T&amp;gt; void    checked_array_delete(T * p);&lt;/p&gt;&lt;p &gt;&lt;b&gt;Требует:&lt;/b&gt; &lt;b&gt;T&lt;/b&gt; должен быть полным типом.    Выражение &lt;tt&gt;delete [] p&lt;/tt&gt;      должно быть синтаксически верным. &lt;/p&gt;&lt;p &gt;&lt;b&gt;Эффекты:&lt;/b&gt; &lt;tt&gt;delete [] p;&lt;/tt&gt; &lt;/p&gt;&lt;p &gt;checked_deleter&lt;/p&gt;&lt;pre&gt;template&amp;lt;class T&amp;gt; struct checked_deleter
{
    typedef void result_type;
    typedef T * argument_type;
    void operator()(T * p) const;
};

&lt;/pre&gt;&lt;p &gt;void checked_deleter&amp;lt;T&amp;gt;::operator()(T * p) const;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Требует:&lt;/b&gt; &lt;b&gt;T&lt;/b&gt; должен быть полным типом (complete type).    Выражение &lt;tt&gt;delete p&lt;/tt&gt;     должно быть синтаксически верным. &lt;/p&gt;&lt;p&gt;&lt;b&gt;Эффекты:&lt;/b&gt; &lt;tt&gt;delete p;&lt;/tt&gt; &lt;/p&gt;&lt;p &gt;checked_array_deleter&lt;/p&gt;&lt;pre&gt;template&amp;lt;class T&amp;gt; struct checked_array_deleter
{
    typedef void result_type;
    typedef T * argument_type;
    void operator()(T * p) const;
};
&lt;/pre&gt;&lt;p &gt;void checked_array_deleter&amp;lt;T&amp;gt;::operator()(T * p) const;&lt;/p&gt;&lt;p &gt;&lt;b&gt;Требует:&lt;/b&gt; &lt;b&gt;T&lt;/b&gt; должен быть полным типом.    Выражение &lt;tt&gt;delete [] p&lt;/tt&gt;     должно быть синтаксически верным. &lt;/p&gt;&lt;p &gt;&lt;b&gt;Эффекты:&lt;/b&gt; &lt;tt&gt;delete [] p;&lt;/tt&gt; &lt;/p&gt;&lt;p &gt;&lt;a name="Acknowledgements"&gt;&lt;/a&gt;Благодарности&lt;/p&gt;&lt;p &gt;   Шаблоны функций checked_delete и    checked_array_delete    изначально были частью boost/utility.hpp, и     документация была разработана с участием Beman Dawes, Dave Abrahams, Vladimir     Prus, Rainer Deyke, John Maddock, и др.   &lt;/p&gt;&lt;h3&gt;            &lt;a name="functions_next_prior"&gt;&lt;/a&gt;Шаблоны функций next() и              prior()&lt;/h3&gt;&lt;p &gt;Определенные типы данных,         такие как итераторы категорий forward и         bidirectional          &lt;a href="http://www.solarix.ru/for_developers/cpp/stl/stl.shtml"&gt;стандартной библиотеки         C++&lt;/a&gt;, &amp;nbsp;не          поддерживают операции сложения и вычитания через&amp;nbsp;          operator+() или operator-().&amp;nbsp;          Это означает, что не-модифицирующие вычисления          последующего и предыдущего значения требуют создания временного объекта,         даже если operator++() или operator--()          допустимы.&amp;nbsp;Это также означает, что          написание кода типа &lt;code&gt;itr+1&lt;/code&gt; внутри шаблона ограничивает          категорию итератора в рамках          &lt;a href="http://www.solarix.ru/for_developers/cpp/stl/stl.shtml#random_iterator"&gt;random access&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Функции next() и         prior() предоставляют простой способ          избежать этих проблем:&lt;/p&gt;&lt;blockquote&gt;            &lt;pre&gt;template &amp;lt;class T&amp;gt;
T next(T x) { return ++x; }

template &amp;lt;class T, class Distance&amp;gt;

T next(T x, Distance n)
{
    std::advance(x, n);
    return x;
}

template &amp;lt;class T&amp;gt;
T prior(T x) { return --x; }

template &amp;lt;class T, class Distance&amp;gt;
T prior(T x, Distance n)
{
    std::advance(x, -n);
    return x;
}&lt;/pre&gt;&lt;/blockquote&gt;&lt;p&gt;Использование предельно просто:&lt;/p&gt;&lt;blockquote&gt;            &lt;pre&gt;const std::list&amp;lt;T&amp;gt;::iterator p = get_some_iterator();
const std::list&amp;lt;T&amp;gt;::iterator prev = boost::prior(p);
const std::list&amp;lt;T&amp;gt;::iterator next = boost::next(prev, 2);&lt;/pre&gt;&lt;/blockquote&gt;&lt;p &gt;Расстояние от заданного итератора должно                  быть задано абсолютной величиной. К примеру,                 итератор, отстоящий на 4 шага                  итератора от заданного итератора &lt;code&gt;p&lt;/code&gt;                 может быть получен как &lt;code&gt;prior(p, 4)&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Функции создал&lt;b&gt; Dave Abrahams&lt;/b&gt;.          Версии с двумя аргументами создал &lt;b&gt;Daniel Walker&lt;/b&gt;.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h3&gt;&lt;a name="Class_noncopyable"&gt;&lt;/a&gt;Класс noncopyable&lt;/h3&gt;&lt;p&gt;Класс noncopyable является базовым.&amp;nbsp;Пользовательский          класс должен наследовать от noncopyable,         чтобы запретить создание объектов через копирование и копирование          через присваивание.&lt;/p&gt;&lt;p &gt;Некоторые объекты, в          частности те, которые управляют сложными          ресурсами (файлами или сетевыми сессиями),         не поддерживают семантику копирования.           Иногда семантика копирования в принципе возможна,         но она имеет либо весьма ограниченную полезность,         либо слишком сложна для правильной реализации.          Иногда Вы разрабатываете класс, который просто          не нужно копировать, и Вы не желаете тратить          время на написание соответствующих функций.          Наследование от noncopyable              предотвращает создание компилятором по умолчанию конструктора          копирования и оператора присваивания, что          предотвращает других программистов от ошибочного использования класса.&lt;/p&gt;&lt;p &gt;Обычный способ решения проблемы заключается в          объявлении приватных конструктора копирования и оператора присваивания,          и затем документирования причин, по которым          это сделано. Но наследование от класса         noncopyable проще и очевиднее,         и не тредбует дополнительного документирования.&lt;/p&gt;&lt;p &gt;Программа noncopyable_test.cpp          может быть использована для проверки правильного функционирования класса         noncopyable. Она успешно откомпилирована          с помощью GCC 2.95, Metrowerks CodeWarrior 5.0,          и&amp;nbsp; Microsoft Visual C++ 6.0 sp 3.&lt;/p&gt;&lt;p&gt;Создатель: &lt;b&gt;Dave Abrahams&lt;/b&gt;.&lt;/p&gt;&lt;p &gt;Пример&lt;/p&gt;&lt;blockquote&gt;            &lt;pre&gt;// inside one of your own headers ...
#include &amp;lt;boost/utility.hpp&amp;gt;

class ResourceLadenFileSystem : boost::noncopyable {
...&lt;/pre&gt;&lt;/blockquote&gt;&lt;p &gt;Обоснование&lt;/p&gt;&lt;p &gt;Класс noncopyable          имеет защищенные конструктор и деструктор,          чтобы подчеркнуть тот факт, что он          используется только как базовый класс.&amp;nbsp;Dave          Abrahams сделал замечание о возможном негативном влиянии на          компиляторную оптимизацию кода после добавления (даже пустого)          деструктора. Он заявил: &amp;quot;Возможно,         эти опасения беспочвенны, потому что         noncopyable будет использован главным          образом для классов, которые управляют          ресурсами и таким образом имеют нетривиальные деструкторы&amp;quot;.&lt;/p&gt;&lt;h3&gt;&lt;a name="addressof"&gt;&lt;/a&gt;Шаблон функции addressof()&lt;/h3&gt;&lt;p&gt;Функция addressof() возвращает адерс          объекта.&lt;/p&gt;&lt;blockquote&gt;            &lt;pre&gt;template &amp;lt;typename T&amp;gt; inline T*                addressof(T&amp;amp; v);
template &amp;lt;typename T&amp;gt; inline const T*          addressof(const T&amp;amp; v);
template &amp;lt;typename T&amp;gt; inline volatile T*       addressof(volatile T&amp;amp; v);
template &amp;lt;typename T&amp;gt; inline const volatile T* addressof(const volatile T&amp;amp; v);

&lt;/pre&gt;&lt;/blockquote&gt;&lt;p &gt;C++ разрешает программисту заменять унарный          оператор в классе         operator&amp;amp;()          для получения адреса объекта. Получение истинного адреса объекта требует          неуклюжих тюков с преобразованием (casting),          чтобы избежать вызова перегруженного оператора&amp;nbsp; operator&amp;amp;().          Функция addressof()          обеспечивает обертку для необходимого кода&amp;lt;           чтобы упростить получение истинного адреса объекта.         &lt;/p&gt;&lt;p&gt;Программа addressof_test.cpp может быть          использована для проверки правильной работы функции         addressof().&lt;/p&gt;&lt;p&gt;Добавил: &lt;b&gt;Brad King&lt;/b&gt; на основе идей,         возникших в дискуссии с &lt;b&gt;Doug          Gregor&lt;/b&gt;.&lt;/p&gt;&lt;p &gt;Пример&lt;/p&gt;&lt;blockquote&gt;            &lt;pre&gt;#include &amp;lt;boost/utility.hpp&amp;gt;

struct useless_type {};
class nonaddressable {
  useless_type operator&amp;amp;() const;
};

void f() {
  nonaddressable x;
  nonaddressable* xp = boost::addressof(x);
  // nonaddressable* xpe = &amp;amp;x; /* error */
}&lt;/pre&gt;&lt;/blockquote&gt;&lt;p&gt;P.S.: Нагло спёрто отсюда: &lt;a href="http://www.solarix.ru/for_developers/cpp/boost/utility/ru/utility.shtml"&gt;BOOST C++: заголовочный файл boost/utility.hpp&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1252038906587337119-7171886092468429530?l=rakafon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rakafon.blogspot.com/feeds/7171886092468429530/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://rakafon.blogspot.com/2009/04/boostutility.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/7171886092468429530'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/7171886092468429530'/><link rel='alternate' type='text/html' href='http://rakafon.blogspot.com/2009/04/boostutility.html' title='Использование boost::utility'/><author><name>Rakafon</name><uri>http://www.blogger.com/profile/03386514126069055282</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-wnns05XIxW4/Ti7XTMmujOI/AAAAAAAAABg/rZpn54sM7BI/s1600/20168127'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1252038906587337119.post-2967213272639974053</id><published>2009-04-01T19:20:00.001+03:00</published><updated>2010-10-15T14:37:28.540+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='boost'/><category scheme='http://www.blogger.com/atom/ns#' term='cpp'/><title type='text'>Использование boost::multi_index</title><content type='html'>&lt;p&gt;Все типы Boost.MultiIndex объявлены в пространстве имен &lt;code&gt;boost::multi_index&lt;/code&gt;. Дополнительно в пространство boost включены шаблонный класс multi_index_container и глобальные функции get и project. Для краткости большинство приводимых фрагментов кода предполагают предшествующее расширение области видимости:&lt;/p&gt;&lt;pre style="width:320px;"&gt;using namespace ::boost;
using namespace ::boost::multi_index;
&lt;/pre&gt;&lt;lj-cut text="Читать далее ..."&gt;   &lt;h2&gt;Введение&lt;/h2&gt;&lt;p&gt;Мы предлагаем ознакомится с основными концепциями Boost.MultiIndex на паре простых примеров.&lt;/p&gt;&lt;h3&gt;Проведение различных сортировок одного множества&lt;/h3&gt;&lt;p&gt;Шаблоны STL set и multiset являются массивами переменной длины, где элементы отсортированы согласно установленному сравнительному предикату (критерию). Эти контейнерные класс немногим способны помочь программисту, когда ему необходимо сортировать и искать элементы опираясь на &lt;i&gt;несколько &lt;/i&gt;критериев. Взгляните на пример:&lt;/p&gt;&lt;pre&gt;struct employee
{
int id;
std::string name;
employee(int id,const std::string&amp;amp; name):id(id),name(name){}
bool operator&amp;lt;(const employee&amp;amp; e)const{return id&amp;lt;e.id;}
};
&lt;/pre&gt;&lt;p&gt;Тот факт, что ID-ключ является уникальным для каждого служащего, определяет возможность перегрузки оператора «&amp;lt;», что в свою очередь позволяет держать такие переменные типа employee в контейнере &lt;code&gt;std::set&amp;lt;employee&amp;gt;&lt;/code&gt;. Теперь, если мы хотим вывести список работников в алфавитном порядке, мы столкнемся с рядом трудностей и недостатков, начиная от неразумного расходования памяти, кончая громоздкостью и ненаглядностью кода. Вот, что первое приходит в голову:&lt;/p&gt;&lt;p&gt;Копировать переменную типа &lt;code&gt;std::set&amp;lt;employee&amp;gt;&lt;/code&gt; в переменную типа &lt;code&gt;vector&lt;/code&gt; и в качестве критерия сортировки определить функтор, работающий с полем структуры name.&lt;/p&gt;&lt;p&gt;Хранить кроме основного массива еще массив указателей на его элементы, соответственно отсортированный по полю name.&lt;/p&gt;&lt;p&gt;Их этих двух решений, пожалуй, второе принимается большинством программистов, заботящимся о быстродействии, однако оно предполагает постоянно в программе «тащить» вместо одной структуры – две. Если от такого кода потребовать еще и устойчивости к исключительным ситуациям, то поддерживать такую конструкцию становится невозможным.&lt;/p&gt;&lt;p&gt;Boost.MultiIndex отличает от других контейнеров наличие нескольких интерфейсов доступа (индексов упорядочения), каждый из которых сортирует элементы по определенному ключу. Этот шаблон разработан, чтобы помочь в решении задач на сортировку, поиск и др. элементов более чем по одному условному критерию. Определение индексов происходит при конкретизации шаблона multi_index_container; через каждый индекс доступ и сортировка будут происходить отдельно, тогда как сами элементы будут храниться в одном и том же контейнере. Задача, поставленная в примере при помощи &lt;code&gt;Boost.MultiIndex&lt;/code&gt; решается следующим образом:&lt;/p&gt;&lt;pre&gt;&lt;i&gt;// определение бииндексированного множества с индексацией по полям name // и ID
&lt;/i&gt;typedef multi_index_container&amp;lt;
employee,
indexed_by&amp;lt;
&lt;i&gt;// сортировка согласно перегруженному оператору “&amp;lt;”
&lt;/i&gt;ordered_unique&amp;lt;identity&amp;lt;employee&amp;gt; &amp;gt;,

&lt;i&gt;// сортировка функтором less&amp;lt;string&amp;gt; по полю name
&lt;/i&gt;ordered_non_unique&amp;lt;member&amp;lt;employee,std::string,&amp;amp;employee::name&amp;gt; &amp;gt;
&amp;gt; 
&amp;gt; employee_set;

void print_out_by_name(const employee_set&amp;amp; es)
{
&lt;i&gt;// установка доступа к элементам по первому индексу
&lt;/i&gt;const employee_set::nth_index&amp;lt;1&amp;gt;::type&amp;amp; name_index=es.get&amp;lt;1&amp;gt;();
&lt;i&gt;// используйте name_index просто как std::set
&lt;/i&gt;std::copy(
name_index.begin(),name_index.end(),
std::ostream_iterator&amp;lt;employee&amp;gt;(std::cout));
}
&lt;/pre&gt;&lt;p&gt;Вместо единственного условного критерия сравнения, как в ассоциативных контейнерах &lt;a href="../../../../stl/stl.shtml"&gt;STL&lt;/a&gt;, &lt;code&gt;multi_index_container&lt;/code&gt; имеет &lt;code&gt;typelist&lt;/code&gt; (список типов), называемый&lt;code&gt; indexed_by&lt;/code&gt;, где конкретизируются типы, вы устанавливаете соответствующие индексы. Доступ через соответствующий индекс получается через get&amp;lt;N&amp;gt;(), где N изменяется от 0 до количества условных критериев минус один. Доступ через 0-ой индекс может осуществляется по умолчанию прямо из объекта &lt;code&gt;multi_index_container&lt;/code&gt; без использования функции &lt;code&gt;get&amp;lt;0&amp;gt;()&lt;/code&gt;. Например, &lt;code&gt;es.begin()&lt;/code&gt; – то же, что и&lt;code&gt; es.get&amp;lt;0&amp;gt;().begin()&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Отметим, что &lt;code&gt;get() &lt;/code&gt;возвращает ссылку на индексированное множество (будем называть множество, имеющее доступ к элементам основного массива, через один из индексов просто ИНДЕКСом) , а не объект. Индекс не может быть сконструирован в самостоятельный объект, отдельный от основного контейнера. Поэтому следующий код&lt;/p&gt;&lt;pre&gt;&lt;i&gt;// неверно: мы забыли &amp;amp; после employee_set::nth_index&amp;lt;1&amp;gt;::type
&lt;/i&gt;const employee_set::nth_index&amp;lt;1&amp;gt;::type name_index=es.get&amp;lt;1&amp;gt;();
&lt;/pre&gt;&lt;p&gt;будет вызывать ошибку, поскольку здесь осуществлена попытка сделать индекс-объект name_index. Это пример типичной ошибки среди пользователей этой библиотеки.&lt;/p&gt;&lt;h3&gt;Двунаправленный список с быстрым поиском&lt;/h3&gt;&lt;p&gt;На этом примере мы продемонстрируем работу так называемых &lt;i&gt;последовательных&lt;/i&gt; &lt;i&gt;индексов&lt;/i&gt;, узнаем, как можно их совместить с индексами упорядочения для построения более функциональных контейнеров. Допустим, мы имеем текст, разбитый на слова и хранящийся в списке, вреде этого:&lt;/p&gt;&lt;pre&gt;typedef std::list&amp;lt;std::string&amp;gt; text_container;

std::string text=
&lt;i&gt;&amp;quot;Alice was beginning to get very tired of sitting by her sister on the &amp;quot;
&amp;quot;bank, and of having nothing to do: once or twice she had peeped into the &amp;quot;
&amp;quot;book her sister was reading, but it had no pictures or conversations in &amp;quot;
&amp;quot;it, 'and what is the use of a book,' thought Alice 'without pictures or &amp;quot;
&amp;quot;conversation?'&amp;quot;&lt;/i&gt;;

&lt;i&gt;// внесение текста в список, используя шаблонный токенайзер из boost
&lt;/i&gt;text_container tc;
boost::tokenizer&amp;lt;boost::char_separator&amp;lt;char&amp;gt; &amp;gt; tok
(text,boost::char_separator&amp;lt;char&amp;gt;(&lt;i&gt;&amp;quot; \t\n.,;:!?'\&amp;quot;-&amp;quot;&lt;/i&gt;));
std::copy(tok.begin(),tok.end(),std::back_inserter(tc));

//Если мы хотим посчитать, сколько раз слово включено в список, мы воспользуемся std::count:
std::size_t occurrences(const std::string&amp;amp; word)
{
return std::count(tc.begin(),tc.end(),word);
}
&lt;/pre&gt;&lt;p&gt;Однако исполнение такого алгоритма будет происходить за линейное время, что может быть неприемлемо в случае больших количеств текста. Аналогично, операция удаления слова из середины списка по времени также весьма затратна в std::list:&lt;/p&gt;&lt;pre&gt;void delete_word(const std::string&amp;amp; word)
{
tc.remove(word); &lt;i&gt;// scans the entire list looking for word
&lt;/i&gt;}
&lt;/pre&gt;&lt;p&gt;Если необходимо представление списка, к примеру, в алфавитном порядке, нам снова необходимо заводить отдельную структуру, индексирующую элементы в tc. Boost.MultiIndex делает это просто комбинируя последовательный и порядковый индексы:&lt;/p&gt;&lt;pre&gt;&lt;i&gt;// объявление multi_index_container со «списковым» индексом и порядковым 
// индексом 
&lt;/i&gt;typedef multi_index_container&amp;lt;
std::string,
indexed_by&amp;lt;
sequenced&amp;lt;&amp;gt;, &lt;i&gt;// «списковый» индекс
&lt;/i&gt;ordered_non_unique&amp;lt;identity&amp;lt;std::string&amp;gt; &amp;gt; &lt;i&gt;// слова в алфавит. Порядке
&lt;/i&gt;&amp;gt;
&amp;gt; text_container;

std::string text=...

&lt;i&gt;// внесение текста в список
&lt;/i&gt;text_container tc;
boost::tokenizer&amp;lt;boost::char_separator&amp;lt;char&amp;gt; &amp;gt; tok
(text,boost::char_separator&amp;lt;char&amp;gt;(&lt;i&gt;&amp;quot; \t\n.,;:!?'\&amp;quot;-&amp;quot;&lt;/i&gt;));
std::copy(tok.begin(),tok.end(),std::back_inserter(tc));
&lt;/pre&gt;&lt;p&gt;До сих пор, замена &lt;code&gt;std::list &lt;/code&gt;на &lt;code&gt;multi_index_container&lt;/code&gt; не давала особых преимуществ. Код для вставки текста в контейнер не изменился, поскольку последовательный индекс предоставляет интерфейс доступа, полностью аналогичный таковому у &lt;code&gt;std::list&lt;/code&gt; (нет необходимости обращаться к этому индексу через &lt;code&gt;get&amp;lt;0&amp;gt;()&lt;/code&gt;, поскольку, как было сказано выше, &lt;code&gt;multi_index_container&lt;/code&gt; наследует весь интерфейс своего нулевого индекса.) Однако введение дополнительного порядкового индекса позволит нам выполнять процедуры подсчета слов и удаления слов более эффективно:&lt;/p&gt;&lt;pre&gt;std::size_t occurrences(const std::string&amp;amp; word)
{
&lt;i&gt;// устанавливаем доступ через №1 индекс
&lt;/i&gt;text_container::nth_index&amp;lt;1&amp;gt;::type&amp;amp; sorted_index=tc.get&amp;lt;1&amp;gt;();

&lt;i&gt;// используем sorted_index просто как std::set
&lt;/i&gt;return sorted_index.count(word);
}

void delete_word(const std::string&amp;amp; word)
{
&lt;i&gt;// устанавливаем доступ через №1 индекс
&lt;/i&gt;text_container::nth_index&amp;lt;1&amp;gt;::type&amp;amp; sorted_index=tc.get&amp;lt;1&amp;gt;();

&lt;i&gt;// используем sorted_index просто как std::set
&lt;/i&gt;sorted_index.erase(word);
}
&lt;/pre&gt;&lt;p&gt;Теперь процедуры occurrences и delete_word выполняются за логарифмическое время. Программист может использовать №0 индекс для доступа к исходному тексту (как &lt;code&gt;std::list&lt;/code&gt;) или использовать №1 индекс, когда необходим логарифмический поиск.&lt;/p&gt;&lt;h2&gt;Определение индексов&lt;/h2&gt;&lt;p&gt;Индексы в конкретизации multi_index_container объявляются внутри специальной конструкции &lt;u&gt;indexed_by&lt;/u&gt;. Например, &amp;nbsp;конкретизация:&lt;/p&gt;&lt;pre&gt;typedef multi_index_container&amp;lt;
employee,
indexed_by&amp;lt;
ordered_unique&amp;lt;identity&amp;lt;employee&amp;gt; &amp;gt;,
ordered_non_unique&amp;lt;member&amp;lt;employee,std::string,&amp;amp;employee::name&amp;gt; &amp;gt;
&amp;gt; 
&amp;gt; employee_set;
включает &lt;u&gt;уникальный порядковый индекс &lt;/u&gt;и &lt;u&gt;неуникальный порядковый индекс&lt;/u&gt;, а, следующим кодом:
typedef multi_index_container&amp;lt;
std::string,
indexed_by&amp;lt;
sequenced&amp;lt;&amp;gt;,
ordered_non_unique&amp;lt;identity&amp;lt;std::string&amp;gt; &amp;gt;
&amp;gt;
&amp;gt; text_container;
&lt;/pre&gt;&lt;p&gt;мы установили два индекса, первый &lt;u&gt;последовательного типа&lt;/u&gt;, а второй – неуникальный &lt;u&gt;порядковый индекс&lt;/u&gt;. В общем случае мы можем объявлять произвольное число индексов: каждый аргумент конструкции indexed_by называется &lt;u&gt;спецификатором индекса&lt;/u&gt;. В зависимости от типа индекса, объявление соответствующего спецификатора будет требовать дополнительной информации: например, спецификаторы ordered_unique и ordered_non_unique требуют указания &lt;u&gt;ключевого поля&lt;/u&gt; и (необязательно) &lt;u&gt;сравнительного условного предиката&lt;/u&gt;; вместе они полностью определяют, как будет производиться сортировка.&lt;/p&gt;&lt;p&gt;конкретизация multi_index_container может быть объявлена без конструкции indexed_by: в таком случае индексация по умолчанию производится таким образом, что конкретизированный шаблон эквивалентен конкретизированному std::set. Если конкретно - &amp;nbsp;конкретизация&lt;/p&gt;&lt;pre&gt;multi_index_container&amp;lt;&lt;i&gt;(element)&lt;/i&gt;&amp;gt;
аналогична
multi_index_container&amp;lt;
&lt;i&gt;(element)&lt;/i&gt;,
indexed_by&amp;lt;
ordered_unique&amp;lt;identity&amp;lt;(element)&amp;gt; &amp;gt;
&amp;gt;
&amp;gt;
&lt;/pre&gt;&lt;h2&gt;Метки&lt;/h2&gt;&lt;p&gt;С целью получения доступа к индексу данного multi_index_container, программист должен помнить порядковый номер этого индекса в списке indexed_by. Однако такое обращение к индексу является неуклюжим и ненаглядным, поэтому в спецификатор индекса введен такой (необязательный) параметр, как метка (tag). Она всегда ставится первым параметром в соответствующем спецификаторе. Вот как будет выглядеть наш тип employee_set с использованием меток:&lt;/p&gt;&lt;pre&gt;&lt;i&gt;// метки
&lt;/i&gt;struct name{};

typedef multi_index_container&amp;lt;
employee,
indexed_by&amp;lt;
ordered_unique&amp;lt;identity&amp;lt;employee&amp;gt; &amp;gt;,
ordered_non_unique&amp;lt;tag&amp;lt;name&amp;gt;,member&amp;lt;employee,std::string,&amp;amp;employee::name&amp;gt; &amp;gt;
&amp;gt;
&amp;gt; employee_set;
&lt;/pre&gt;&lt;p&gt;Метка должна быть описана внутри конструкции tag. Любой тип может быть использован в качестве метки индекса, хотя, в основном, выбирают названия, которые так или иначе описывают индекс. Вызов соответствующего индекса по метке выглядит так:&lt;/p&gt;&lt;pre&gt;typedef employee_set::index&amp;lt;name&amp;gt;::type employee_set_by_name;
employee_set_by_name::iterator it=es.get&amp;lt;name&amp;gt;().begin();
&lt;/pre&gt;&lt;p&gt;Если метка для индекса не определена (как в случае №0 индекса в предыдущем примере), доступ к данному индексу предоставляется только по его номеру. Отметим, что typedef-конструкции для получения доступа к индексу через номер и через метку различны. Например:&lt;/p&gt;&lt;pre&gt;// тип переменной доступа к индексу #1,
employee_set::nth_index&amp;lt;1&amp;gt;::type
// тип переменной доступа к индексу, меченному name (в данном случая эти два определения эквивалентны)
employee_set::index&amp;lt;name&amp;gt;::type
&lt;/pre&gt;&lt;p&gt;Наоборот, метод get() перегружен и используется одинаково в обоих случаях:&lt;/p&gt;&lt;pre&gt;employee_set::index&amp;lt;name&amp;gt;::type&amp;amp; name_index=es.get&amp;lt;name&amp;gt;();
employee_set::nth_index&amp;lt;1&amp;gt;::type&amp;amp; name_index2=es.get&amp;lt;1&amp;gt;(); &lt;i&gt;// тот же индекс
&lt;/pre&gt;&lt;/i&gt;   &lt;p&gt;К тому же шаблон класса tag может получать в качестве параметров несколько меток для одного индекса: например, спецификация №1 индекса в предыдущем примере может быть переписана с использованием двух различных меток name и by_name:&lt;/p&gt;&lt;pre&gt;&lt;i&gt;// метки
&lt;/i&gt;struct name{};
struct by_name{};

typedef multi_index_container&amp;lt;
...
ordered_non_unique&amp;lt;
tag&amp;lt;name,by_name&amp;gt;,
member&amp;lt;employee,std::string,&amp;amp;employee::name&amp;gt;
&amp;gt;
...
&amp;gt; employee_set;
&lt;/pre&gt;&lt;h2&gt;Типы индексов&lt;/h2&gt;&lt;p&gt;В настоящее время &lt;code&gt;Boost.MultiIndex&lt;/code&gt; имеет следующие типы индексов:&lt;/p&gt;&lt;p align="justify"&gt;Порядковые индексы сортируют элементы как &lt;code&gt;std::set&lt;/code&gt;-ы и предоставляют аналогичный интерфейс. Они могут быть двух вариантов: уникальные и неуникальные; первые не позволяют хранить идентичные элементы, тогда как вторые – позволяют (как &lt;code&gt;std::multiset&lt;/code&gt;)&lt;/p&gt;&lt;p align="justify"&gt;Последовательные индексы разработаны по образу и подобию &lt;code&gt;std::list&lt;/code&gt; : они хранят элементы аналогично двунаправленному списку.&lt;/p&gt;&lt;p&gt;Пример во введении демонстрирует использование всех видов индексов.&lt;/p&gt;&lt;h3&gt;Порядковые индексы&lt;/h3&gt;&lt;p&gt;Порядковые индексы сортируют элементы &lt;code&gt;multi_index_container&lt;/code&gt; согласно заданному ключевому полю и заданному сравнительному предикату. Доступ через эти индексы аналогичен работе с контейнерами &lt;code&gt;std::set&lt;/code&gt;, и более того – полностью копируют их интерфейс, хотя присутствуют некоторые небольшие отличия, диктуемые общими принципами Boost.MultiIndex.&lt;/p&gt;&lt;h4&gt;Уникальный и неуникальный варианты&lt;/h4&gt;&lt;p&gt;Последовательные индексы могут быть описаны как &lt;i&gt;уникальные&lt;/i&gt;, тогда они запрещают наличие двух элементов с одинаковыми значениями ключевого поля, и &lt;i&gt;неуникальные&lt;/i&gt;, которые это позволяют. Посмотрим снова на инсталляцию&lt;/p&gt;&lt;pre&gt;typedef multi_index_container&amp;lt;
employee,
indexed_by&amp;lt;
ordered_unique&amp;lt;identity&amp;lt;employee&amp;gt; &amp;gt;,
ordered_non_unique&amp;lt;member&amp;lt;employee,std::string,&amp;amp;employee::name&amp;gt; &amp;gt;
&amp;gt; 
&amp;gt; employee_set;
&lt;/pre&gt;&lt;p&gt;Первый индекс объявлен как уникальный (поскольку поле ID уникально для каждого рабочего) и поэтому описан как тип ordered_unique, тогда как второй индекс неуникален (поскольку два Джона Смита могут служить в одной компании) и соответственно описан как ordered_non_unique.&lt;/p&gt;&lt;p&gt;Разделение порядковых индексов на уникальный и неуникальные влияет на то, какие элементы можно вставлять в multi_index_container. Короче включение через уникальный порядковый индекс проходит аналогично включению в std::set, тогда как через неуникальный – аналогично std::multiset. Например, employee_set может содержать структуры employee(0, “George Brown”) и employee(1, “George Brown”), но добавить структуру с таким же ID, какой там уже имеется, нельзя.&lt;/p&gt;&lt;p&gt;В конкретизации multi_index_container может быть объявлено несколько уникальных индексов. Например, если мы собираем данные об ИНН работников, который также уникален, мы можем организовать контейнер таким образом:&lt;/p&gt;&lt;pre&gt;struct employee
{
int id;
std::string name;
int ssnumber;

employee(int id,const std::string&amp;amp; name,int ssnumber):
id(id),name(name),ssnumber(ssnumber){}

bool operator&amp;lt;(const employee&amp;amp; e)const{return id&amp;lt;e.id;}
};

typedef multi_index_container&amp;lt;
employee,
indexed_by&amp;lt;
&lt;i&gt;// сортировать по employee::operator&amp;lt;
&lt;/i&gt;ordered_unique&amp;lt;identity&amp;lt;employee&amp;gt; &amp;gt;,

&lt;i&gt;// сортировать согласно less&amp;lt;string&amp;gt; по полю name
&lt;/i&gt;ordered_non_unique&amp;lt;member&amp;lt;employee,std::string,&amp;amp;employee::name&amp;gt; &amp;gt;,

&lt;i&gt;// сортировать согласно less&amp;lt;int&amp;gt; по полю ssnumber
&lt;/i&gt;ordered_unique&amp;lt;member&amp;lt;employee,int,&amp;amp;employee::ssnumber&amp;gt; &amp;gt;
&amp;gt;
&amp;gt; employee_set;
&lt;/pre&gt;&lt;h4&gt;Спецификация индексов&lt;/h4&gt;&lt;p&gt;Синтаксис спецификатора порядкового индекса в поле шаблона indexed_by выглядит следующим образом:&lt;/p&gt;&lt;pre&gt;(ordered_unique | ordered_non_unique)
&amp;lt;[&lt;i&gt;(tag)&lt;/i&gt;[,&lt;i&gt;(key extractor)&lt;/i&gt;[,&lt;i&gt;(comparison predicate)&lt;/i&gt;]]]&amp;gt;

(ordered_unique | ordered_non_unique)
&amp;lt;[&lt;i&gt;(key extractor)&lt;/i&gt;[,&lt;i&gt;(comparison predicate)&lt;/i&gt;]]&amp;gt;
&lt;/pre&gt;&lt;p&gt;Первый необязательный аргумент используется, когда индексу приписывается &lt;u&gt;метка&lt;/u&gt;. Сейчас мы немного поговорим об остальных двух.&lt;/p&gt;&lt;h4&gt;Ключевое поле&lt;/h4&gt;&lt;p&gt;Первым параметром шаблона спецификации индекса (или второй, если есть метка) является ключевое поле. Этот параметр передает ссылку на элемент (в нашем примере на всю структуру employee) и частично информацию о способе сортировки таких элементов. Вот основные варианты определения ключевого поля:&lt;/p&gt;&lt;p&gt;Целый элемент служит ключом, как в случае первого индекса в employee_set. А для определения ключевого поля можно использовать; identity как раз используется, когда ключом является целый объект.&lt;/p&gt;&lt;p&gt;Сравнение осуществляется по отдельному полю структуры элемента – это очень напоминает работу с индексами отдельной колонки реляционной базы данных. Boost.MultiIndex имеет шаблон member, который возвращает ключ на поле структуры, определяемое указателем&lt;/p&gt;&lt;p&gt;В качестве примера снова рассмотри наш employee_set. Первый индекс:&lt;/p&gt;&lt;pre&gt;ordered_unique&amp;lt;identity&amp;lt;employee&amp;gt; &amp;gt;
&lt;/pre&gt;&lt;p&gt;определяется при помощи identity, причем объект элемента выступает в качестве ключа. Теперь посмотрим на второй индекс:&lt;/p&gt;&lt;pre&gt;ordered_non_unique&amp;lt;member&amp;lt;employee,std::string,&amp;amp;employee::name&amp;gt; &amp;gt;
&lt;/pre&gt;&lt;p&gt;Здесь мы используем шаблон member, чтобы определяем (извлекаем) ключ из поля структуры employee. Тип этого ключа – std::string.&lt;/p&gt;&lt;p&gt;Другой общий случай – когда сортировка производится по заданной функции-члену класса элемента. Это напоминает случай вычисляемого индекса в некоторых реляционных БД. В таких случаях ключ не является переменной-членом структуры элемента, а получает значение из заданной функции-члена. Boost.MultiIndex поддерживает такой механизм «извлечения» ключа посредством шаблона const_mem_fun. Рассмотрим расширение нашего примера, когда сортировка по третьему индексу проводится на основе длины поля name:&lt;/p&gt;&lt;pre&gt;struct employee
{
int id;
std::string name;

employee(int id,const std::string&amp;amp; name):id(id),name(name){}

bool operator&amp;lt;(const employee&amp;amp; e)const{return id&amp;lt;e.id;}

&lt;i&gt;// возвращает длину поля name
&lt;/i&gt;std::size_t name_length()const{return name.size();}
};

typedef multi_index_container&amp;lt;
employee,
indexed_by&amp;lt;
&lt;i&gt;// сортировать согласно employee::operator&amp;lt;
&lt;/i&gt;ordered_unique&amp;lt;identity&amp;lt;employee&amp;gt; &amp;gt;,

&lt;i&gt;// сортировать согласно less&amp;lt;string&amp;gt; по полю name
&lt;/i&gt;ordered_non_unique&amp;lt;member&amp;lt;employee,std::string,&amp;amp;employee::name&amp;gt; &amp;gt;,

&lt;i&gt;// сортировать согласно less&amp;lt;int&amp;gt; по ключу name_length()
&lt;/i&gt;ordered_non_unique&amp;lt;
const_mem_fun&amp;lt;employee,std::size_t,&amp;amp;employee::name_length&amp;gt;
&amp;gt;
&amp;gt;
&amp;gt; employee_set;
&lt;/pre&gt;&lt;p&gt;&lt;u&gt;Пример 2&lt;/u&gt; в разделе примеров содержит законченную программу, демонстрирующую использование const_mem_fun. Почти всегда, используются именно константные функции-члены, поскольку в multi_index_container-е (как и в std::set-е) элементы предполагаются постоянными. Однако шаблон mem_fun предоставляет вам возможность использовать неконстантные функции-члены. Их использование и применение подробно обсуждено в параграфе о дополнительных характеристиках ключевых полей Boost MultiIndex в разделе дополнительной информации.&lt;/p&gt;&lt;p&gt;Более сложные типы контейнеров могут потребовать &lt;i&gt;сложных&lt;/i&gt; &lt;i&gt;ключей&lt;/i&gt;, собирающих информацию сразу от нескольких ключевых полей. Сложные ключи введены в Boost.MultiIndex при помощи конструкции &lt;code&gt;composite_key&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;&lt;code&gt;identity&lt;/code&gt;, &lt;code&gt;member&lt;/code&gt; и &lt;code&gt;const_mem_fun&lt;/code&gt; (или их комбинации при помощи &lt;code&gt;composite_key&lt;/code&gt;) наиболее часто используемые шаблоны, используемые для разработки &lt;code&gt;multi_index_container&lt;/code&gt;-ов. Однако пользователь имеет возможность написать собственную процедуру «извлечения» ключа для более экзотических ситуаций, чем те, которые предполагает данная концепция. В примере №6 демонстрируется использование нескольких технологий «извлечения» ключа, которые необходимы когда доступ к элементам и/или ключам осуществляется через указатели.&lt;/p&gt;&lt;h4&gt;Условные предикаты сравнения&lt;/h4&gt;&lt;p&gt;И наконец, последнее поле спецификатора порядкового индекса – это предикат (критерий) сравнения, который представляет из себя оператор «меньше» (на деле – функтор), определенных для типа ключа. Этот критерий не отличается от таковых, использующихся в контейнерах &lt;a href="../../../../stl/stl.shtml"&gt;STL&lt;/a&gt;, таких как &lt;code&gt;std::set&lt;/code&gt;. По умолчанию (если поле предиката в спецификаторе не заполнено), индекс с ключом типа key_type сортирует элементы согласно функтору &lt;code&gt;std::less&amp;lt;key_type&amp;gt;&lt;/code&gt;. Если требуется определить какой-то другой критерий сравнения, ссылка на него дается в конце объявления индекса:&lt;/p&gt;&lt;pre&gt;&lt;i&gt;// определяет полииндексированное множество с индексами по id и name
// в обратном алфавитном порядке
&lt;/i&gt;typedef multi_index_container&amp;lt;
employee,
indexed_by&amp;lt;
ordered_unique&amp;lt;identity&amp;lt;employee&amp;gt; &amp;gt;, &lt;i&gt;// обычный индекс
&lt;/i&gt;ordered_non_unique&amp;lt;
member&amp;lt;employee,std::string,&amp;amp;employee::name&amp;gt;,
std::greater&amp;lt;std::string&amp;gt; &lt;i&gt;//по умолчанию std::less&amp;lt;std::string&amp;gt;
&lt;/i&gt;&amp;gt;
&amp;gt;
&amp;gt; employee_set;
&lt;/pre&gt;&lt;h4&gt;Специальные функции поиска&lt;/h4&gt;&lt;p&gt;Наличие порядкового индекса позволяет проводить поиск элементов согласно определенному для этого индекса ключу. Например, чтобы найти Веронику Круз в employee_set вы можете написать:&lt;/p&gt;&lt;pre&gt;employee_set es;
...
typedef employee_set::index&amp;lt;name&amp;gt;::type employee_set_by_name;
employee_set_by_name::iterator it=es.get&amp;lt;name&amp;gt;().find(&lt;i&gt;&amp;quot;Veronica Cruz&amp;quot;&lt;/i&gt;);
&lt;/pre&gt;&lt;p&gt;Кроме того, Boost.MultiIndex предоставляет специальные операции поиска, который ведется по ключу, отличному по типу от key_type-а нашего индекса. Это оказывается чрезвычайно полезным, когда затратно создавать переменные типа key_type. Последовательные контейнеры &lt;a href="../../../../stl/stl.shtml"&gt;STL&lt;/a&gt; не имеют аналогичных возможностей, поэтому приходится прибегать к неэлегантным обходным путям. Например, рассмотрим задачу определения рабочих, чьи ID лежат в промежутке [0,100]. Принимая во внимание, что ключ индекса №0 это сам элемент employee, можем для начала написать следующее:&lt;/p&gt;&lt;pre&gt;employee_set::iterator p0=es.lower_bound(employee(0,&lt;i&gt;&amp;quot;&amp;quot;&lt;/i&gt;));
employee_set::iterator p1=es.upper_bound(employee(100,&lt;i&gt;&amp;quot;&amp;quot;&lt;/i&gt;));
&lt;/pre&gt;&lt;p&gt;Однако помните, что std::less&amp;lt;employee&amp;gt; в действительности сравнивает ID рабочих, поэтому более уместно было бы запретить создание структуры employee целиком, а извлекать только их ID. Boost.MultiIndex предлагает для этой цели определить другой критерий-функтор:&lt;/p&gt;&lt;pre&gt;struct comp_id
{
&lt;i&gt;// compare an ID and an employee
&lt;/i&gt;bool operator()(int x,const employee&amp;amp; e2)const{return x&amp;lt;e2.id;}

&lt;i&gt;// compare an employee and an ID
&lt;/i&gt;bool operator()(const employee&amp;amp; e1,int x)const{return e1.id&amp;lt;x;}
};
&lt;/pre&gt;&lt;p&gt;и написать теперь уже:&lt;/p&gt;&lt;pre&gt;employee_set::iterator p0=es.lower_bound(0,comp_id());
employee_set::iterator p1=es.upper_bound(100,comp_id());
&lt;/pre&gt;&lt;p&gt;Здесь в ходе поиска мы не просто перебираем ID элементов вместо перебор целых employee-структур, мы создаем новый критерий поиска. В общем, если мы хотим перегрузить критерии поиска, мы должны позаботиться об их совместимости. Если не прибегать к строгим определениям (а их вы можете найти в главе «MultiIndex: Руководство»), то критерии называются совместимыми, когда любая последовательность, отсортированная по одному из них также отсортирована и по другому. Вот более интересный пример сортировки:&lt;/p&gt;&lt;pre&gt;&lt;i&gt;// сортировка по инициалам
&lt;/i&gt;struct comp_initial
{
bool operator()(char ch,const std::string&amp;amp; s)const{
if(s.empty())return false;
return ch&amp;lt;s[0];
}

bool operator()(const std::string&amp;amp; s,char ch)const{
if(s.empty())return true;
return s[0]&amp;lt;ch;
}
};

&lt;i&gt;// получение первого рабочего с именем на 'J' (сортировка по имени)
&lt;/i&gt;typedef employee_set::index&amp;lt;name&amp;gt;::type employee_set_by_name;
employee_set_by_name&amp;amp; name_index=es.get&amp;lt;name&amp;gt;(); 
employee_set_by_name::const_iterator it=
name_index.lower_bound(&lt;i&gt;'J'&lt;/i&gt;,comp_initial());
&lt;/pre&gt;&lt;h4&gt;Получение диапазонов&lt;/h4&gt;&lt;p&gt;Диапазонный поиск, то есть поиск всех элементов данного интервала – очень частая операция, для которой стандартные &lt;code&gt;lower_bound&lt;/code&gt; и &lt;code&gt;upper_bound&lt;/code&gt; могут быть использованы, разве что в простейших случаях. Например, этот код отбирает элементы &lt;code&gt;multi_index_container&amp;lt;double&amp;gt;&lt;/code&gt;, расположенные в интервале [100; 200]:&lt;/p&gt;&lt;pre&gt;typedef multi_index_container&amp;lt;double&amp;gt; double_set;
&lt;i&gt;// напомним, что параметры при конркретизации по умолчанию:
// multi_index_container&amp;lt;double,indexed_by&amp;lt;unique&amp;lt;identity&amp;lt;double&amp;gt; &amp;gt; &amp;gt; &amp;gt;.
&lt;/i&gt;
double_set s;
...
double_set::iterator it0=s.lower_bound(100.0);
double_set::iterator it1=s.upper_bound(200.0);
&lt;i&gt;// диапазон [it0,it1) содержит элементы [100,200]
&lt;/pre&gt;&lt;/i&gt;   &lt;p&gt;Небольшие изменения в код следует внести, если мы хотим сделать одну из границ интервала нестрогой. Если мы, к примеру, ищем элементы интервала (100, 200), то писать надо так:&lt;/p&gt;&lt;pre&gt;double_set::iterator it0=s.upper_bound(100.0);
double_set::iterator it1=s.lower_bound(200.0);
&lt;i&gt;// диапазон [it0,it1) содержит элементы (100;200)
&lt;/pre&gt;&lt;/i&gt;   &lt;p&gt;Чтобы внести в код такое усложнение, аккуратный программист обязан принимать во внимание, что верхняя и нижняя границы интервала – вещи нестрогие. Если, к примеру, нижняя грань 200, а верхняя – 100, итераторы it0 и it1, определенные в порядке, обратном приведенному, не будут охватывать никакого диапазона. При попытке пройтись в цикле по элементам от it0 до it1 вы вполне можете проворонить исключение. Эти особенности делают поиск диапазона стандартными &lt;a href="../../../../stl/stl.shtml"&gt;STL&lt;/a&gt; функциями ненаглядным и незащищенным.&lt;/p&gt;&lt;p&gt;Встроенная функция &lt;a href="http://www.boost.org/libs/multi_index/doc/reference/ord_indices.html#range_operations"&gt;&lt;u&gt;range&lt;/u&gt;&lt;/a&gt;, часто в сочетании с выражениями &lt;u&gt;&lt;a href="http://www.boost.org/libs/lambda/index.html"&gt;Boost.Lambda&lt;/a&gt;&lt;/u&gt;, может сильно облегчить программирование такого рода поисков. Взгляните:&lt;/p&gt;&lt;pre&gt;using namespace boost::lambda;

typedef multi_index_container&amp;lt;double&amp;gt; double_set;
double_set s;
...
std::pair&amp;lt;double_set::iterator,double_set::iterator&amp;gt; p=
s.range(100.0&amp;lt;=_1,_1&amp;lt;=200); &lt;i&gt;// 100&amp;lt;= x &amp;lt;=200
&lt;/i&gt;...
p=s.range(100.0&amp;lt;_1,_1&amp;lt;200); &lt;i&gt;// 100&amp;lt; x &amp;lt; 200
&lt;/i&gt;...
p=s.range(100.0&amp;lt;=_1,_1&amp;lt;200); &lt;i&gt;// 100&amp;lt;= x &amp;lt; 200
&lt;/i&gt;Одна или обе границы могут быть обозначены ключевым словом unbounded (неограничен):
p=s.range(100.0&amp;lt;=_1,unbounded); &lt;i&gt;// 100 &amp;lt;= x
&lt;/i&gt;p=s.range(unbounded,_1&amp;lt;200.0); &lt;i&gt;// x &amp;lt; 200
&lt;/i&gt;p=s.range(unbounded,unbounded); &lt;i&gt;// то же, что std::make_pair(s.begin(),s.end())
&lt;/pre&gt;&lt;/i&gt;   &lt;h4&gt;Обновление&lt;/h4&gt;&lt;p&gt;Встроенная функция &lt;a href="http://www.boost.org/libs/multi_index/doc/reference/ord_indices.html#replace"&gt;&lt;u&gt;replace&lt;/u&gt;&lt;/a&gt; выполняет замену в месте, указанном итератором:&lt;/p&gt;&lt;pre&gt;typedef index&amp;lt;employee_set,name&amp;gt;::type employee_set_by_name;
employee_set_by_name&amp;amp; name_index=es.get&amp;lt;name&amp;gt;();

employee_set_by_name::iterator it=name_index.find(&lt;i&gt;&amp;quot;Anna Jones&amp;quot;&lt;/i&gt;);
employee anna=*it;
anna.name=&lt;i&gt;&amp;quot;Anna Smith&amp;quot;&lt;/i&gt;; &lt;i&gt;// она уже вышла за муж за К. Смита
&lt;/i&gt;name_index.replace(it,anna); &lt;i&gt;// обновляем запись
&lt;/pre&gt;&lt;/i&gt;   &lt;p&gt;&lt;code&gt;replace&lt;/code&gt;-процедура имеет в данном случае ряд особенности:&lt;/p&gt;&lt;p&gt;Выполнение ее происходит за постоянное время, если элемент после замены остается на то же месте, относительно &lt;i&gt;всех&lt;/i&gt; индексов; в обратном случае она происходит за логарифмическое время.&lt;/p&gt;&lt;p&gt;Корректность итератора и ссылки проверяется.&lt;/p&gt;&lt;p&gt;Вся процедура выполнена защищенной от исключений, т.е. &lt;code&gt;multi_index_container&lt;/code&gt; остается неизменными даже в том случае, если система или пользовательский тип данных возбуждает исключение в ходе выполнения процедуры.&lt;/p&gt;&lt;p&gt;&lt;code&gt;replace&lt;/code&gt; – очень полезная функция, не объявленная в стандартах &lt;a href="../../../../stl/stl.shtml"&gt;STL&lt;/a&gt;, очень удобна как раз когда требуется надежная защита от исключительных ситуаций.&lt;/p&gt;&lt;p&gt;Наблюдательный читатель может заметить, что удобство процедуры replace «влетает в копеечку»: элемент копируется целиком &lt;i&gt;дважды&lt;/i&gt;. Первый раз при получении замещающего элемента, второй – при вставлении его в контейнер. Если структура громоздка для копирования, будет выгоднее модифицировать отдельные поля элемента. Для этого в Boost.MultiIndex введен альтернативный механизм обновления – функция &lt;a href="http://www.boost.org/libs/multi_index/doc/reference/ord_indices.html#modify"&gt;&lt;u&gt;modify&lt;/u&gt;&lt;/a&gt;:&lt;/p&gt;&lt;pre&gt;struct change_name
{
change_name(const std::string&amp;amp; new_name):new_name(new_name){}
void operator()(employee&amp;amp; e)
{
e.name=new_name;
}

private:
std::string new_name;
};
...
typedef employee_set::index&amp;lt;name&amp;gt;::type employee_set_by_name;
employee_set_by_name&amp;amp; name_index=es.get&amp;lt;name&amp;gt;();

employee_set_by_name::iterator it=name_index.find(&lt;i&gt;&amp;quot;Anna Jones&amp;quot;&lt;/i&gt;);
name_index.modify(it,change_name(&lt;i&gt;&amp;quot;Anna Smith&amp;quot;&lt;/i&gt;));
&lt;/pre&gt;&lt;p&gt;Функция Modify получает на вход функтор (или указатель на функцию), который модифицирует элемент, тем самым, избавляя программиста от необходимости создавать лишнюю структуру, как это нужно было бы в случае replace. Так же, как и replace, эта функция хорошо защищена и сохраняет информацию контейнера при сбоях. Однако механизм ее действия не полностью аналогичен механизму replace. Рассмотрим, что происходит, если в результате замены возникает повтор по уникальному индексу. В случае replace, исходное значение поля будет возвращено и функция завершится, никак не повлияв на контейнер. В случае modify, такой возможности у функции нет, поэтому ошибочный элемент, появившийся в результате модификации, будет немедленно удалее, а функция вернет false. Это различие необходимо должно учитываться программистом при выборе между функциями replace и modify.&lt;/p&gt;&lt;p&gt;Аналогично modify, объявлена функция для модификации ключевого поля -- &lt;a href="http://www.boost.org/libs/multi_index/doc/reference/ord_indices.html#modify_key"&gt;&lt;u&gt;modify_key&lt;/u&gt;&lt;/a&gt;. В таком случае модифицирующий функтор получает ссылку на поле key_value элемента контейнера, а не на весь элемент. Обратите внимание, что такие модификации возможны (разумеется, иначе никак), только в том случае, когда ключ не извлекается специальными процедурами (как const_mem_fun), а получается прямо из поля структуры элемента&lt;/p&gt;&lt;pre&gt;struct change_str
{
change_str(const std::string&amp;amp; new_str):new_str(new_str){}

&lt;i&gt;// работает со строкой, не со структурой employee
&lt;/i&gt;void operator()(std::string&amp;amp; str)
{
str=new_str;
}

private:
std::string new_str;
};
...
typedef employee_set::index&amp;lt;name&amp;gt;::type employee_set_by_name;
employee_set_by_name&amp;amp; name_index=es.get&amp;lt;name&amp;gt;();

employee_set_by_name::iterator it=name_index.find(&lt;i&gt;&amp;quot;Anna Jones&amp;quot;&lt;/i&gt;);
name_index.modify_key(it,change_str(&lt;i&gt;&amp;quot;Anna Smith&amp;quot;&lt;/i&gt;));
&lt;/pre&gt;&lt;p&gt;Точно так же, как и modify, modify_key удаляет элемент, если результат модификации вызывает противоречие в каком-то из индексов. Modify и modify_key позволяют использование удобного синтаксиса &lt;u&gt;&lt;a href="http://www.boost.org/libs/lambda/index.html"&gt;Boost.Lambda&lt;/a&gt;&lt;/u&gt; в указании модификаторов:&lt;/p&gt;&lt;pre&gt;using namespace boost::lambda;

typedef employee_set::index&amp;lt;name&amp;gt;::type employee_set_by_name;
employee_set_by_name&amp;amp; name_index=es.get&amp;lt;name&amp;gt;();

employee_set_by_name::iterator it=name_index.find(&lt;i&gt;&amp;quot;Anna Jones&amp;quot;&lt;/i&gt;);
name_index.modify_key(it,_1=&lt;i&gt;&amp;quot;Anna Smith&amp;quot;&lt;/i&gt;);
&lt;/pre&gt;&lt;h3&gt;Последовательные индексы&lt;/h3&gt;&lt;p&gt;В отличие от порядковых индексов, последовательные индексы не имеют фиксированного правила следования элементов – наоборот, элементы могут быть помещены в любую точку последовательности (как в std::list). Интерфейс последовательных индексов, соответственно задуман очень похожим на std::list, по крайней мере, все функции std::list здесь продублированы. Их реализация может быть слегка отличной по аргументам и/или семантике, дабы удовлетворять единой концепции Boost.MultiIndex. В частности, имеется существенное ограничение в доступе к элементам через последовательный индекс: изменение элементов multi_index_container через итератор запрещено:&lt;/p&gt;&lt;pre&gt;multi_index_container&amp;lt;
int,
indexed_by&amp;lt;sequenced&amp;lt;&amp;gt; &amp;gt;
&amp;gt; s; &lt;i&gt;// контейнер-список
&lt;/i&gt;
s.push_front(0);
*(s.begin()) = 1; &lt;i&gt;// ERROR: элементы нельзя изменять ТАК
&lt;/pre&gt;&lt;/i&gt;   &lt;p&gt;Получается, что итераторы последовательного индекса (в действительности, любого индекса) указывают на константные элементы. Это ограничение может показаться странным, однако оно продиктовано принципами работы multi_index_container-а. Если мы позволим изменять элементы &lt;i&gt;таким&lt;/i&gt; образом, мы можем нарушить целостность других индексов контейнера. Изменение элементов может быть осуществлено &lt;i&gt;только&lt;/i&gt; посредством &lt;u&gt;&lt;a href="http://64.4.54.250/C:/Documents%20and%20Settings/SVETA/Рабочий%20стол/CPP/boost_translate/tutorial.html#seq_updating%23seq_updating"&gt;&amp;nbsp;функций обновления&lt;/a&gt;&lt;/u&gt;.&lt;/p&gt;&lt;p&gt;Если в нашем multi_index_container-е есть два или более индексов, один из которых последовательный, при вставлении элемента посредством любого непоследовательного индекса, элемент автоматически добавляется в конец последовательного. Пример поможет вам понять это:&lt;/p&gt;&lt;pre&gt;multi_index_container&amp;lt;
int,
indexed_by&amp;lt;
sequenced&amp;lt;&amp;gt;, &lt;i&gt;// последовательный тип
&lt;/i&gt;ordered_unique&amp;lt;identity&amp;lt;int&amp;gt; &amp;gt; &lt;i&gt;// дополнительный день
&lt;/i&gt;&amp;gt;
&amp;gt; s;

s.get&amp;lt;1&amp;gt;().insert(1); &lt;i&gt;// вставка «1» посредством индекса #1
&lt;/i&gt;s.get&amp;lt;1&amp;gt;().insert(0); &lt;i&gt;// вставка «0» посредством индекса #1

// список элементов, упорядоченных по индексу #0
&lt;/i&gt;std::copy(s.begin(),s.end(),std::ostream_iterator&amp;lt;int&amp;gt;(std::cout));
&lt;i&gt;// результат: 1 0
&lt;/pre&gt;&lt;/i&gt;   &lt;p&gt;Таким образом, последовательные индексы располагают элементы в порядке их вставления, даже если вставка производилась посредством непоследовательного индекса.&lt;/p&gt;&lt;h4&gt;Спецификация&lt;/h4&gt;&lt;p&gt;Последовательные индексы описываются при помощи шаблона sequenced:&lt;/p&gt;&lt;p&gt;sequenced&amp;lt;[&lt;i&gt;(tag)&lt;/i&gt;]&amp;gt;&lt;/p&gt;&lt;p&gt;Параметр &lt;u&gt;&lt;a href="http://64.4.54.250/C:/Documents%20and%20Settings/bugenina/Рабочий%20стол/COMCON_files/boost_translate/tutorial.html#tagging%23tagging"&gt;tag&lt;/a&gt;&lt;/u&gt; является необязательным.&lt;/p&gt;&lt;h4&gt;Функции списка&lt;/h4&gt;&lt;p&gt;Как было отмечено ранее, последовательные индексы довольно точно копируют интерфейс std::list (большинство функций практически идентичны). Однако семантика и внутренняя организация таких процедур совпадает далеко не всегда. Еще раз повторим, что эти отличия диктуются тем, что вставка элемента может повлечь за собой разрушение внутренней структуры других индексов multi_index_container. Для более подробной информации смотрите &lt;u&gt;&lt;a href="http://www.boost.org/libs/multi_index/doc/reference/index.html"&gt;руководство&lt;/a&gt;&lt;/u&gt;.&lt;/p&gt;&lt;h4&gt;Обновление&lt;/h4&gt;&lt;p&gt;Так же, как и порядковые индексы, последовательные индексы предоставляют аналогичные функции &lt;a href="http://www.boost.org/libs/multi_index/doc/reference/seq_indices.html#modify"&gt;&lt;u&gt;modify&lt;/u&gt;&lt;/a&gt; и &lt;a href="http://www.boost.org/libs/multi_index/doc/reference/seq_indices.html#replace"&gt;&lt;u&gt;replace&lt;/u&gt;&lt;/a&gt;. Однако аналога modify_key нет, поскольку порядковые индексы не имеют ключа.&lt;/p&gt;&lt;h2&gt;Проекция итераторов&lt;/h2&gt;&lt;p&gt;Если в нашем multi_index_container-е определены два индекса i1 и i2, то при помощи функции &lt;a href="http://www.boost.org/libs/multi_index/doc/reference/multi_index_container.html#projection"&gt;&lt;u&gt;project&lt;/u&gt;&lt;/a&gt; можно получить значение i1-итератора некоего элемента по известному i2-итератору того же элемента. Эта процедура позволяет программисту быстро перемещаться между различными индексами multi_index_container-а. Рассмотрим пример:&lt;/p&gt;&lt;pre&gt;typedef employee_set::index&amp;lt;name&amp;gt;::type employee_set_by_name;
employee_set_by_name&amp;amp; name_index=es.get&amp;lt;name&amp;gt;();

&lt;i&gt;// Список работников, упорядоченных по ID, начиная с ID Роберта Брауна
&lt;/i&gt;
employee_set_by_name::iterator it1=name_index.find(&lt;i&gt;&amp;quot;Robert Brown&amp;quot;&lt;/i&gt;);
&lt;i&gt;
// получение итератора по 0-индексу из it1
&lt;/i&gt;employee_set::iterator it2=es.project&amp;lt;0&amp;gt;(it1); 

std::copy(it2,es.end(),std::ostream_iterator&amp;lt;employee&amp;gt;(std::cout));
&lt;/pre&gt;&lt;p&gt;Чуть более сложный пример:&lt;/p&gt;&lt;pre&gt;text_container tc;

&lt;i&gt;// доступ к элементам через #1 (индекс, упорядоченный по словам)
&lt;/i&gt;text_container::nth_index&amp;lt;1&amp;gt;::type&amp;amp; sorted_index=tc.get&amp;lt;1&amp;gt;();

&lt;i&gt;// вставка &amp;quot;older&amp;quot; после каждой из &amp;quot;sister&amp;quot;
&lt;/i&gt;
text_container::nth_index_iterator&amp;lt;1&amp;gt;::type it1=
sorted_index.lower_bound(&lt;i&gt;&amp;quot;sister&amp;quot;&lt;/i&gt;);

while(it1!=sorted_index.end()&amp;amp;&amp;amp;*it1==&lt;i&gt;&amp;quot;sister&amp;quot;&lt;/i&gt;){
&lt;i&gt;// преобразование итератора в итератор последовательного индекса
&lt;/i&gt;text_container::iterator it2=tc.project&amp;lt;0&amp;gt;(it1);

tc.insert(it2,&lt;i&gt;&amp;quot;older&amp;quot;&lt;/i&gt;);
++it1;
}
&lt;/pre&gt;&lt;p&gt;При необходимости может быть использован в сочетании с &lt;u&gt;&lt;a href="http://64.4.54.250/C:/Documents%20and%20Settings/bugenina/Рабочий%20стол/COMCON_files/boost_translate/tutorial.html#tagging%23tagging"&gt;tags&lt;/a&gt;&lt;/u&gt;.&lt;/p&gt;&lt;h2&gt;Безопасность и дополнительные возможности&lt;/h2&gt;&lt;p&gt;multi_index_container предосталяет дополнительные возможности и гарантирует определенный уровень безопасности, как это делает &lt;a href="../../../../stl/stl.shtml"&gt;STL&lt;/a&gt;. Обращение к элементам через итераторы защищено в смысле операций вставки, замены и редактирования элементов.&lt;/p&gt;&lt;p&gt;Конкретизация multi_index_container может быть проведена абсолютно аналогично std::set, std::multiset и (с небольшими ограничениями) std::list, см. &lt;u&gt;&lt;a href="http://www.boost.org/libs/multi_index/doc/advanced_topics.html#simulate_std_containers"&gt;дополнительные вопросы&lt;/a&gt;&lt;/u&gt;. Эта аналогия продолжается не только на синтаксис, но и на эффективность выполнения операций. Для получения дополнительной информациии касательно дополнительных функций смотри &lt;u&gt;&lt;a href="http://www.boost.org/libs/multi_index/doc/reference/index.html"&gt;руководство&lt;/a&gt;&lt;/u&gt;. Для получения данных о производительности multi_index_container - смотрите &lt;u&gt;&lt;a href="http://www.boost.org/libs/multi_index/doc/performance.html"&gt;презентацию&lt;/a&gt;&lt;/u&gt;.&lt;/p&gt;&lt;!--EndFragment--&gt; &lt;p&gt;P.S.: ... Нагло утянуто отсюда: &lt;a href="http://www.solarix.ru/for_developers/cpp/boost/multi_index/ru/an/multi_index.shtml"&gt;BOOST C++: Multi_Index&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1252038906587337119-2967213272639974053?l=rakafon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rakafon.blogspot.com/feeds/2967213272639974053/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://rakafon.blogspot.com/2009/04/boostmultiindex.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/2967213272639974053'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/2967213272639974053'/><link rel='alternate' type='text/html' href='http://rakafon.blogspot.com/2009/04/boostmultiindex.html' title='Использование boost::multi_index'/><author><name>Rakafon</name><uri>http://www.blogger.com/profile/03386514126069055282</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-wnns05XIxW4/Ti7XTMmujOI/AAAAAAAAABg/rZpn54sM7BI/s1600/20168127'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1252038906587337119.post-898933748335509226</id><published>2009-04-01T19:00:00.001+03:00</published><updated>2010-10-15T14:37:33.216+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='boost'/><category scheme='http://www.blogger.com/atom/ns#' term='cpp'/><title type='text'>Использование библиотеки boost::signals</title><content type='html'>&lt;div &gt;&lt;p&gt;Нередко при проектировании систем возникают задачи следующего характера. В системе появляется сущность, являющаяся генератором (источником) некоторых событий. И есть ряд других сущностей, которые должны быть уведомлены о возникновении этих событий. Простейший пример – на некоторой интерфейсной форме есть кнопка, по клику на которой необходимо выполнить некоторый код. Кнопка – источник события. Класс формы – получатель уведомления о возникновении события и его обработчик. В книге «Паттерны проектирования» от GoF такое взаимодействие сущностей описано как паттерн «Команда» или «Действие». Непосредственной поддержки описанного механизма подписки-уведомления в языке С++ (в отличии от C#, например) нет. Но реализацию этого механизма можно найти в boost. А именно – в библиотеке boost::signal.  Описанный простейший пример с кнопкой и формой будет выглядеть следующим образом: &lt;/p&gt;&lt;lj-cut text="Читать дальше ..."&gt;  &lt;pre &gt;&lt;span &gt;#include &amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span &gt;#include &amp;lt;boost/signal.hpp&amp;gt;&lt;/span&gt;
&lt;span &gt;#include &amp;lt;boost/bind.hpp&amp;gt;&lt;/span&gt;

&amp;nbsp;
&lt;span &gt;//////////////////////////////////////////////////////////////////////////////////////////&lt;/span&gt;
&lt;span &gt;// Класс кнопки&lt;/span&gt;
&lt;span &gt;// Пример класса-источника событий&lt;/span&gt;
&lt;span &gt;//////////////////////////////////////////////////////////////////////////////////////////&lt;/span&gt;
&lt;span &gt;class&lt;/span&gt; SampleButton
&lt;span &gt;&amp;#123;&lt;/span&gt;
&lt;span &gt;public&lt;/span&gt;&lt;span &gt;:&lt;/span&gt;
 &lt;span &gt;// Метод, добавляющий новый обработчик события&lt;/span&gt;

 &lt;span &gt;// h - функтор, реализующий обработчик&lt;/span&gt;
 &lt;span &gt;void&lt;/span&gt; SetOnClick&lt;span &gt;&amp;#40;&lt;/span&gt;boost&lt;span &gt;::&lt;/span&gt;&lt;span &gt;function&lt;/span&gt;&lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;void&lt;/span&gt;&lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt; h&lt;span &gt;&amp;#41;&lt;/span&gt; 
 &lt;span &gt;&amp;#123;&lt;/span&gt;
  &lt;span &gt;// Присоединяем к событию новый обоаботчик&lt;/span&gt;

  m_OnClick.&lt;span &gt;connect&lt;/span&gt;&lt;span &gt;&amp;#40;&lt;/span&gt;h&lt;span &gt;&amp;#41;&lt;/span&gt;;
 &lt;span &gt;&amp;#125;&lt;/span&gt;
 &lt;span &gt;// Метод, инициирущий событие&lt;/span&gt;
 &lt;span &gt;void&lt;/span&gt; FireOnClick&lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt; &lt;span &gt;&amp;#123;&lt;/span&gt;m_OnClick&lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt;;&lt;span &gt;&amp;#125;&lt;/span&gt;

&lt;span &gt;private&lt;/span&gt;&lt;span &gt;:&lt;/span&gt;
 &lt;span &gt;// Член данных, хранящий коллекцию обработчиков события OnClick&lt;/span&gt;
 boost&lt;span &gt;::&lt;/span&gt;&lt;span &gt;signal&lt;/span&gt;&lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;void&lt;/span&gt; &lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt; m_OnClick;
&lt;span &gt;&amp;#125;&lt;/span&gt;;
&amp;nbsp;
&lt;span &gt;//////////////////////////////////////////////////////////////////////////////////////////&lt;/span&gt;

&lt;span &gt;// Класс формы&lt;/span&gt;
&lt;span &gt;// Пример класса-обработчика событий&lt;/span&gt;
&lt;span &gt;//////////////////////////////////////////////////////////////////////////////////////////&lt;/span&gt;
&lt;span &gt;class&lt;/span&gt; SampleForm
&lt;span &gt;&amp;#123;&lt;/span&gt;
&lt;span &gt;public&lt;/span&gt;&lt;span &gt;:&lt;/span&gt;
 &lt;span &gt;// Конструктор&lt;/span&gt;
 SampleForm&lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt;

 &lt;span &gt;&amp;#123;&lt;/span&gt;
  &lt;span &gt;// Добавляем к каждой кнопке обработчики события OnClick&lt;/span&gt;
  m_Button1.&lt;span &gt;SetOnClick&lt;/span&gt;&lt;span &gt;&amp;#40;&lt;/span&gt;boost&lt;span &gt;::&lt;/span&gt;&lt;span &gt;bind&lt;/span&gt;&lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;&amp;amp;&lt;/span&gt;SampleForm&lt;span &gt;::&lt;/span&gt;&lt;span &gt;Handler1&lt;/span&gt;, &lt;span &gt;this&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt;;
  m_Button2.&lt;span &gt;SetOnClick&lt;/span&gt;&lt;span &gt;&amp;#40;&lt;/span&gt;boost&lt;span &gt;::&lt;/span&gt;&lt;span &gt;bind&lt;/span&gt;&lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;&amp;amp;&lt;/span&gt;SampleForm&lt;span &gt;::&lt;/span&gt;&lt;span &gt;Handler2&lt;/span&gt;, &lt;span &gt;this&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt;;
  m_Button3.&lt;span &gt;SetOnClick&lt;/span&gt;&lt;span &gt;&amp;#40;&lt;/span&gt;boost&lt;span &gt;::&lt;/span&gt;&lt;span &gt;bind&lt;/span&gt;&lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;&amp;amp;&lt;/span&gt;SampleForm&lt;span &gt;::&lt;/span&gt;&lt;span &gt;Handler2&lt;/span&gt;, &lt;span &gt;this&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt;;
  m_Button3.&lt;span &gt;SetOnClick&lt;/span&gt;&lt;span &gt;&amp;#40;&lt;/span&gt;boost&lt;span &gt;::&lt;/span&gt;&lt;span &gt;bind&lt;/span&gt;&lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;&amp;amp;&lt;/span&gt;SampleForm&lt;span &gt;::&lt;/span&gt;&lt;span &gt;Handler1&lt;/span&gt;, &lt;span &gt;this&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt;;
 &lt;span &gt;&amp;#125;&lt;/span&gt;

&amp;nbsp;
 &lt;span &gt;// Тестовый обработчик события&lt;/span&gt;
 &lt;span &gt;void&lt;/span&gt; Handler1&lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt;
 &lt;span &gt;&amp;#123;&lt;/span&gt;
  std&lt;span &gt;::&lt;/span&gt;&lt;span &gt;cout&lt;/span&gt; &lt;span &gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span &gt;&amp;quot;Handler 1 entered&amp;quot;&lt;/span&gt; &lt;span &gt;&amp;lt;&amp;lt;&lt;/span&gt; std&lt;span &gt;::&lt;/span&gt;&lt;span &gt;endl&lt;/span&gt;;
 &lt;span &gt;&amp;#125;&lt;/span&gt;

&amp;nbsp;
 &lt;span &gt;// Тестовый обработчик события&lt;/span&gt;
 &lt;span &gt;void&lt;/span&gt; Handler2&lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt;
 &lt;span &gt;&amp;#123;&lt;/span&gt;
  std&lt;span &gt;::&lt;/span&gt;&lt;span &gt;cout&lt;/span&gt; &lt;span &gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span &gt;&amp;quot;Handler 2 entered&amp;quot;&lt;/span&gt; &lt;span &gt;&amp;lt;&amp;lt;&lt;/span&gt; std&lt;span &gt;::&lt;/span&gt;&lt;span &gt;endl&lt;/span&gt;;
 &lt;span &gt;&amp;#125;&lt;/span&gt;

&amp;nbsp;
 &lt;span &gt;// Пример кнопок&lt;/span&gt;
 SampleButton m_Button1;
 SampleButton m_Button2;
 SampleButton m_Button3;
&lt;span &gt;&amp;#125;&lt;/span&gt;;
&amp;nbsp;
&lt;span &gt;int&lt;/span&gt; main&lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;int&lt;/span&gt; argc, &lt;span &gt;char&lt;/span&gt;&lt;span &gt;**&lt;/span&gt; argv&lt;span &gt;&amp;#41;&lt;/span&gt;

&lt;span &gt;&amp;#123;&lt;/span&gt;
 &lt;span &gt;// Создаем форму&lt;/span&gt;
 SampleForm form;
&amp;nbsp;
 &lt;span &gt;// Для каждой кнопки на форме инициируем событие OnClick&lt;/span&gt;
 form.&lt;span &gt;m_Button1&lt;/span&gt;.&lt;span &gt;FireOnClick&lt;/span&gt;&lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt;;
 form.&lt;span &gt;m_Button2&lt;/span&gt;.&lt;span &gt;FireOnClick&lt;/span&gt;&lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt;;
 form.&lt;span &gt;m_Button3&lt;/span&gt;.&lt;span &gt;FireOnClick&lt;/span&gt;&lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt;;

&amp;nbsp;
 &lt;span &gt;// Вывод на консоль следующий&lt;/span&gt;
 &lt;span &gt;// Handler 1 entered&lt;/span&gt;
 &lt;span &gt;// Handler 2 entered&lt;/span&gt;
 &lt;span &gt;// Handler 2 entered&lt;/span&gt;
 &lt;span &gt;// Handler 1 entered&lt;/span&gt;
 &lt;span &gt;return&lt;/span&gt; &lt;span &gt;0&lt;/span&gt;;

&lt;span &gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;Что, собственно, здесь происходит. &lt;/p&gt;&lt;ol&gt;&lt;li &gt;&lt;div &gt;Объявляется член данных, описывающий событие. В этом примере это SampleButton::m_OnClick. Тип этого члена данных – boost::signal. Этот класс – шаблонный, и в качестве обязательного параметра принимает сигнатуру обработчика сигнала. В примере эта сигнатура – void (). Т. е. обработчик не принимает параметров и ничего не возвращает.&lt;/div&gt;&lt;/li&gt;
&lt;li &gt;&lt;div &gt;Реализуется метод, осуществляющий подписку на соответствующее событие. В примере – это метод AddOnClick. Подписка осуществляется с помощью метода signal::connect, в который передается обработчик, с которым необходимо связать событие.&lt;/div&gt;&lt;/li&gt;
&lt;li &gt;&lt;div &gt;Где-то в коде производится инициация события. В данном случае это делается в методе SampleButton::FireOnClick. Инициация события производится путем применения оператора () к члену данных, описывающего событие. В данном случае – к члену m_OnClick. &lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt; Класс boost::signal реализует концепцию функционального объекта, по этому для инициации события, как сказано выше, достаточно применить к этому классу оператор вызова функции. При этом аргументы, передаваемые при вызове, должны соответствовать сигнатуре, переданной в качестве параметра шаблона при объявлении соответствующего члена данных. &lt;/p&gt;&lt;p&gt;Как видно из примера, на одно событие можно назначить сразу несколько обработчиков. При этом (в простейшем случае) будут вызваны все назначенные обработчики. Правда, последовательность их вызова разработчиками библиотеки не гарантируется. Нередко для обозначения сущности, описывающей событие (члена данных m_OnClick) используется термин &lt;em&gt;сигнал&lt;/em&gt; (signal). А для обозначения подписчиков на это событие – термин &lt;em&gt;слот&lt;/em&gt; (slot). В частности, эта терминология используется в оригинальной документации на эту библиотеку. &lt;/p&gt;&lt;/div&gt;&lt;h2&gt;&lt;a  &gt;Объявление объекта-сигнала&lt;/a&gt;&lt;/h2&gt;&lt;div &gt; &lt;p&gt;Объект-сигнал объявляется как экземпляр класса boost::signal&amp;lt;Sig, Comb, Group, GroupComp, SlotFn&amp;gt;. У этого шаблонного класса первый аргумент является обязательным, и определяет сигнатуру вызова сигнала. Оставшиеся – определяют некоторые аспекты поведения объекта-сигнала, о которых будет рассказано ниже. Примеры объявления объекта-сигнала:  &lt;/p&gt;&lt;pre &gt;boost&lt;span &gt;::&lt;/span&gt;&lt;span &gt;signal&lt;/span&gt;&lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;void&lt;/span&gt; &lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt; sig; &lt;span &gt;// Сигнал без аргументов, который ничего не возвращает&lt;/span&gt;
boost&lt;span &gt;::&lt;/span&gt;&lt;span &gt;signal&lt;/span&gt;&lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;int&lt;/span&gt; &lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;sig; &lt;span &gt;// Сигнал без аргументов, возвращающий целое число&lt;/span&gt;

boost&lt;span &gt;::&lt;/span&gt;&lt;span &gt;signal&lt;/span&gt;&lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;void&lt;/span&gt; &lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;float&lt;/span&gt;, &lt;span &gt;int&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt; sig; &lt;span &gt;// Сигнал, принимающий два аргумента и ничего не возвращающий&lt;/span&gt;&lt;/pre&gt;&lt;p&gt; и т. п. Сигнатура сигнала определяет сигнатуру слотов, которые могут быть присоединены к такому сигналу. Вообще говоря, в ряде случаев требуется точное соответствие сигнатур слотов сигнатуре сигнала. &lt;/p&gt;&lt;p&gt;В случае, если в сигнатуре сигнала указывается, что сигнал принимает параметры, то аргументы, переданные при инициации (вызове) сигнала передаются на вход каждому из слотов, присоединенных к сигналу. В случае, если указывается, что сигнал возвращает некое значение, то (в общем случае) возвращается значение, полученное в результате вызова последнего слота в цепочке. Но такое поведение по-умолчанию может быть изменено. Подробнее об этом – в разделе «комбинирование возвращаемых слотами возвращаемых значений». &lt;/p&gt;&lt;/div&gt;&lt;h2&gt;&lt;a  &gt;Присоединение слотов&lt;/a&gt;&lt;/h2&gt;&lt;div &gt; &lt;p&gt;Слот может быть присоединен к сигналу с помощью метода connect. В общем случае этот метод принимает на вход один аргумент – сущность, реализующую концепцию функционального объекта. Таким образом, к слоту может быть присоединено все что угодно, если к этому примени оператор вызова функции с подходящей сигнатурой. В частности, это означает, что вместе с boost::signal может легко применяться такие компоненты boost, как &lt;a href="/wiki/doku.php?id=doc:cpp:boost:function"  title="doc:cpp:boost:function"&gt;boost::function&lt;/a&gt; и &lt;a href="/wiki/doku.php?id=doc:cpp:boost:bind"  title="doc:cpp:boost:bind"&gt;boost::bind&lt;/a&gt;.  &lt;/p&gt;&lt;/div&gt;&lt;h2&gt;&lt;a  &gt;Указание порядка вызова слотов&lt;/a&gt;&lt;/h2&gt;&lt;div &gt; &lt;p&gt;В случае простого присоединения нескольких слотов к сигналу библиотека, вообще говоря, не специфицирует, в каком порядке будут вызваны соответствующие слотам функции. Если все слоты присоединяются в одном месте, то порядок предсказать можно (вызываться они будут в порядке присоединения). Если же присоединение слотов «размазано по коду», то такое предсказание сделать гораздо сложнее. И, если порядок вызова слотов важен, то его надо специфицировать явно путем специальной формы вызова метода connect:  &lt;/p&gt;&lt;pre &gt;&lt;span &gt;float&lt;/span&gt; foo&lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;int&lt;/span&gt;, &lt;span &gt;int&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt;

&lt;span &gt;&amp;#123;&lt;/span&gt;
 &lt;span &gt;return&lt;/span&gt; &lt;span &gt;1.5&lt;/span&gt;;
&lt;span &gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&lt;span &gt;int&lt;/span&gt; bar&lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;float&lt;/span&gt;, &lt;span &gt;float&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt;
&lt;span &gt;&amp;#123;&lt;/span&gt;
 &lt;span &gt;return&lt;/span&gt; &lt;span &gt;2.5&lt;/span&gt;;

&lt;span &gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
boost&lt;span &gt;::&lt;/span&gt;&lt;span &gt;signal&lt;/span&gt;&lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;float&lt;/span&gt; &lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;int&lt;/span&gt;, &lt;span &gt;int&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt; test_sig;&lt;/pre&gt;&lt;p&gt;В случае такого присоедининия слотов:  &lt;/p&gt;&lt;pre &gt;test_sig.&lt;span &gt;connect&lt;/span&gt;&lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;0&lt;/span&gt;, &lt;span &gt;&amp;amp;&lt;/span&gt;foo&lt;span &gt;&amp;#41;&lt;/span&gt;;
test_sig.&lt;span &gt;connect&lt;/span&gt;&lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;1&lt;/span&gt;, &lt;span &gt;&amp;amp;&lt;/span&gt;bar&lt;span &gt;&amp;#41;&lt;/span&gt;;
std&lt;span &gt;::&lt;/span&gt;&lt;span &gt;cout&lt;/span&gt; &lt;span &gt;&amp;lt;&amp;lt;&lt;/span&gt; test_sig&lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;1.5&lt;/span&gt;, &lt;span &gt;2.5&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt; &lt;span &gt;&amp;lt;&amp;lt;&lt;/span&gt; std&lt;span &gt;::&lt;/span&gt;&lt;span &gt;endl&lt;/span&gt;;&lt;/pre&gt;&lt;p&gt; на экран будет выведено число 1.5.  А в случае такого присоединения:  &lt;/p&gt;&lt;pre &gt;test_sig.&lt;span &gt;connect&lt;/span&gt;&lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;1&lt;/span&gt;, &lt;span &gt;&amp;amp;&lt;/span&gt;foo&lt;span &gt;&amp;#41;&lt;/span&gt;;
test_sig.&lt;span &gt;connect&lt;/span&gt;&lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;0&lt;/span&gt;, &lt;span &gt;&amp;amp;&lt;/span&gt;bar&lt;span &gt;&amp;#41;&lt;/span&gt;;
std&lt;span &gt;::&lt;/span&gt;&lt;span &gt;cout&lt;/span&gt; &lt;span &gt;&amp;lt;&amp;lt;&lt;/span&gt; test_sig&lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;1.5&lt;/span&gt;, &lt;span &gt;2.5&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt; &lt;span &gt;&amp;lt;&amp;lt;&lt;/span&gt; std&lt;span &gt;::&lt;/span&gt;&lt;span &gt;endl&lt;/span&gt;;&lt;/pre&gt;&lt;p&gt; число 2.  &lt;/p&gt;&lt;p&gt;Не сложно понять, что все дело в первом параметре метода connect. В общем случае – это целое число, задающее очередность вызова слотов при инициации сигнала. Но, вообще говоря, это может быть и совсем не целое число, а, например строка. Тип группирующего параметра а также способ их упорядочивания задаются третьим и четвертым шаблонным параметром класса signal (Group и GroupComp). По умолчанию это int и less&amp;lt;int&amp;gt; соответственно. Например: &lt;/p&gt;&lt;pre &gt;boost&lt;span &gt;::&lt;/span&gt;&lt;span &gt;signal&lt;/span&gt;&lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;float&lt;/span&gt; &lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;int&lt;/span&gt;, &lt;span &gt;int&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt;, boost&lt;span &gt;::&lt;/span&gt;&lt;span &gt;last_value&lt;/span&gt;&lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;float&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;, std&lt;span &gt;::&lt;/span&gt;&lt;span &gt;string&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt; test_sig;

&amp;nbsp;
test_sig.&lt;span &gt;connect&lt;/span&gt;&lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;&amp;quot;aaa&amp;quot;&lt;/span&gt;, &lt;span &gt;&amp;amp;&lt;/span&gt;foo&lt;span &gt;&amp;#41;&lt;/span&gt;;
test_sig.&lt;span &gt;connect&lt;/span&gt;&lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;&amp;quot;bbb&amp;quot;&lt;/span&gt;, &lt;span &gt;&amp;amp;&lt;/span&gt;bar&lt;span &gt;&amp;#41;&lt;/span&gt;;
std&lt;span &gt;::&lt;/span&gt;&lt;span &gt;cout&lt;/span&gt; &lt;span &gt;&amp;lt;&amp;lt;&lt;/span&gt; test_sig&lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;1.5&lt;/span&gt;, &lt;span &gt;2.5&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt; &lt;span &gt;&amp;lt;&amp;lt;&lt;/span&gt; std&lt;span &gt;::&lt;/span&gt;&lt;span &gt;endl&lt;/span&gt;;&lt;/pre&gt;&lt;p&gt; Выведет на экран число 2. &lt;/p&gt;&lt;p&gt;У метода connect может быть еще один параметр (последний), определяющий место, куда помещается новый слот при присоединении. Варианты этого параметра – boost::signals::at_front (слот добавляется в начало списка) или boost::signals::at_back (слот добавляется в конец списка). По умолчанию этот параметр равен boost::signals::at_back, т. е. слоты добавляются в конец списка. Если добавляемый слот не содержит идентификатора группы, то (в зависимости от значения этого параметра) он добавляется либо в начало, либо в конец общего списка слотов. В случае указания идентификатора группы этот параметр определяет способ добавления слота в рамках других слотов с тем же идентификатором. Например: &lt;/p&gt;&lt;pre &gt;boost&lt;span &gt;::&lt;/span&gt;&lt;span &gt;signal&lt;/span&gt;&lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;float&lt;/span&gt; &lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;int&lt;/span&gt;, &lt;span &gt;int&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt;, boost&lt;span &gt;::&lt;/span&gt;&lt;span &gt;last_value&lt;/span&gt;&lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;float&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;, std&lt;span &gt;::&lt;/span&gt;&lt;span &gt;string&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt; test_sig;

&amp;nbsp;
test_sig.&lt;span &gt;connect&lt;/span&gt;&lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;&amp;quot;aaa&amp;quot;&lt;/span&gt;, &lt;span &gt;&amp;amp;&lt;/span&gt;foo, boost&lt;span &gt;::&lt;/span&gt;&lt;span &gt;signals&lt;/span&gt;&lt;span &gt;::&lt;/span&gt;&lt;span &gt;at_front&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt;;
test_sig.&lt;span &gt;connect&lt;/span&gt;&lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;&amp;quot;aaa&amp;quot;&lt;/span&gt;, &lt;span &gt;&amp;amp;&lt;/span&gt;bar, boost&lt;span &gt;::&lt;/span&gt;&lt;span &gt;signals&lt;/span&gt;&lt;span &gt;::&lt;/span&gt;&lt;span &gt;at_front&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt;;
std&lt;span &gt;::&lt;/span&gt;&lt;span &gt;cout&lt;/span&gt; &lt;span &gt;&amp;lt;&amp;lt;&lt;/span&gt; test_sig&lt;span &gt;&amp;#40;&lt;/span&gt;&lt;span &gt;1.5&lt;/span&gt;, &lt;span &gt;2.5&lt;/span&gt;&lt;span &gt;&amp;#41;&lt;/span&gt; &lt;span &gt;&amp;lt;&amp;lt;&lt;/span&gt; std&lt;span &gt;::&lt;/span&gt;&lt;span &gt;endl&lt;/span&gt;;&lt;/pre&gt;&lt;p&gt; Выведет на экран число 1.5. &lt;/p&gt;&lt;/div&gt;&lt;p&gt;P.S.: Нагло спёрто отсюда: &lt;a href="http://www.sources.ru/wiki/doku.php?id=doc:cpp:boost:signal"&gt;[[doc:cpp:boost:signal]]&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1252038906587337119-898933748335509226?l=rakafon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rakafon.blogspot.com/feeds/898933748335509226/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://rakafon.blogspot.com/2009/04/boostsignals.html#comment-form' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/898933748335509226'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/898933748335509226'/><link rel='alternate' type='text/html' href='http://rakafon.blogspot.com/2009/04/boostsignals.html' title='Использование библиотеки boost::signals'/><author><name>Rakafon</name><uri>http://www.blogger.com/profile/03386514126069055282</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-wnns05XIxW4/Ti7XTMmujOI/AAAAAAAAABg/rZpn54sM7BI/s1600/20168127'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1252038906587337119.post-5502158470528465127</id><published>2009-04-01T18:40:00.001+03:00</published><updated>2010-10-15T14:38:09.153+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='boost'/><category scheme='http://www.blogger.com/atom/ns#' term='cpp'/><title type='text'>Использование boost::tokenizer</title><content type='html'>&lt;p&gt;Нередко в практике программистов встречаются задачи, когда нужно разобрать строку (как еще иногда говорят - распарсить). Решений этой задачи - множество. Это и простейший поиск очередного символа-разделителя, и регулярные выражения, и специальные алгоритмы (например, из коллекции boost::string_algo). Но иногда логика разбиения строки на части (т. е. логика разбора) может быть ну совсем уж специфичная. Или регулярное выражение получается очень уж навороченное. Или по каким-то причинам библиотека регулярных выражений (тот же boost::regex) неприменима. Тогда на помощь может придти boost::tokenizer.  &lt;/p&gt;&lt;p&gt;Вот пример его использования:&lt;/p&gt;&lt;pre&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;string&amp;gt;
#include &amp;lt;list&amp;gt;

#include &amp;lt;boost/tokenizer.hpp&amp;gt;
#include &amp;lt;boost/iostreams/device/file.hpp&amp;gt; // file_source
#include &amp;lt;boost/iostreams/stream.hpp&amp;gt;      // stream

int _tmain(int argc, _TCHAR* argv[])
{
    try
    {
        // определяем длиннючие типы
        typedef boost::iostreams::file_source file_device_type;
        typedef boost::iostreams::stream&amp;lt;file_device_type&amp;gt; stream_type;
        typedef boost::char_separator&amp;lt;char&amp;gt; token_func_type;
        typedef boost::tokenizer&amp;lt;token_func_type&amp;gt; tokenizer_type;
        typedef std::list&amp;lt;std::string&amp;gt; token_list_type;
        
        // открываем файл
        stream_type strm ( file_device_type("C:\\temp.txt", BOOST_IOS::out|BOOST_IOS::binary) );
        strm &amp;gt;&amp;gt; std::noskipws;
        
        // читаем его содержимое в буфер
        std::string buffer;
        std::copy (
            std::istream_iterator&amp;lt;char&amp;gt;(strm),
            std::istream_iterator&amp;lt;char&amp;gt;(),
            std::back_inserter&amp;lt;std::string&amp;gt;(buffer) );
    
        // разбиваем буфер на токены-слова
        // и помещаем их в список строк
        //boost::tokenizer&amp;lt;&amp;gt; tok(buffer);
        token_func_type sep(" \t\n");
        tokenizer_type tok(buffer, sep);
        token_list_type tokens_list;
        std::copy (
            tok.begin(),
            tok.end(),
            std::back_inserter&amp;lt;token_list_type&amp;gt;(tokens_list) );

        // выводим список на печать
        std::copy (
            tokens_list.begin(),
            tokens_list.end(),
            std::ostream_iterator&amp;lt;std::string&amp;gt;(std::cout, "\n") );
    }
    catch ( std::exception &amp; exc )
    {
        std::cerr &amp;lt;&amp;lt; "Exception: " &amp;lt;&amp;lt; exc.what() &amp;lt;&amp;lt; std::endl;
    }
    return 0;
}
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1252038906587337119-5502158470528465127?l=rakafon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rakafon.blogspot.com/feeds/5502158470528465127/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://rakafon.blogspot.com/2009/04/boosttokenizer.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/5502158470528465127'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/5502158470528465127'/><link rel='alternate' type='text/html' href='http://rakafon.blogspot.com/2009/04/boosttokenizer.html' title='Использование boost::tokenizer'/><author><name>Rakafon</name><uri>http://www.blogger.com/profile/03386514126069055282</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-wnns05XIxW4/Ti7XTMmujOI/AAAAAAAAABg/rZpn54sM7BI/s1600/20168127'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1252038906587337119.post-7396483988769460065</id><published>2009-04-01T18:20:00.001+03:00</published><updated>2010-10-15T14:38:14.109+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='boost'/><category scheme='http://www.blogger.com/atom/ns#' term='cpp'/><title type='text'>Использование boost::lexical_cast</title><content type='html'>&lt;div&gt;    &lt;p&gt;Каждому в своей программисткой практике приходилось сталкиваться с ситуациями, когда необходимо было что-либо преобразовать из строки в, предположим, число, или обратно. В зависимости от того, что, куда и как преобразовывается, для этого можно применять sprintf/sscanf, _itoa/atoi (и другие функции из этой группы), strtoi, и т. п. Все эти методы по своему хороши, но для каждого варианта преобразования необходимо помнить - «а что лучше всего для этого преобразования подходит?» &lt;/p&gt;&lt;p&gt;Стандарт языка C/C++ предусматривает ряд средств для выполнения таких преобразований. Однако они различаются по простоте использования, расширяемости и безопасности.&lt;/p&gt;&lt;p&gt;К примеру, существует ряд ограничений для стандартной для языка C функции atoi:&lt;/p&gt;&lt;ul type="square"&gt;&lt;li&gt;Преобразование выполняется только в одном направлении: из текстовой формы во внутренний тип данных. Обратное преобразование с использованием стандартных функций C требует либо использования неудобной и не совсем безопасной функции sprintf, или потери платформонезависимости при использовании таких функций, как itoa.&lt;/li&gt;
&lt;li&gt;Набор поддерживаемых типов является лишь подмножеством встроенных числовых типов, а именно int, long, и double.&lt;/li&gt;
&lt;li&gt;Этот набор типов не может быть расширен однородным образом. К примеру, преобразование из строкового представления в complex или rational.&lt;/li&gt;
&lt;/ul&gt;&lt;p class="normal_text"&gt;Стандартная функция C strtol имеет те же же основные ограничения, хотя предлагает более аккуратный контроль за процессом преобразования. Однако, в общем случае такой контроль или не требуется, или не используется. Семейство функций scanf предоставляет еще больший контроль, однако им не хватает надежности и простоты использования.&lt;/p&gt;&lt;p class="normal_text"&gt;Стандартная библиотека языка C++ содержит stringstream как возможную основу для обсуждаемого форматирования с преобразованием. Она предлагает удобный набор средств для контроля за форматированием и преобразованием I/O &lt;i&gt;из&lt;/i&gt; и &lt;i&gt;в&lt;/i&gt; произвольный тип через текст. Для простых преобразований непосредственное использование stringstream может быть неудобным (или введения дополнительных локальных переменных и невозможности использования удобной инфиксной формы выражений) или неочевидным и туманным (когда объекты типа stringstream создаются как временные объекты в выражении). Локаль (facets) содержит приемлемый набор средств для контроля за представлением в текстовом виде, однако сложность кода приводит к тому, что использовать эти средства удобно только небольшму количеству программистов.&lt;/p&gt;&lt;p class="normal_text"&gt;Шаблон функции lexical_cast предлагает удобный и целостный подход для поддержки распространенных преобразований в и из произвольных типов, когда они представлены в виде текста. Предлагаемое ей упрощение заключается в использовании удобстве применения в выражениях. Для более сложных преобразований, когда, к примеру, требуется контролировать точность, вместо lexical_cast лучше использовать удобный подход &amp;nbsp;stringstream. Для преобразования одного числа в другое вместо lexical_cast рекомендуется использовать &lt;a href="http://www.solarix.ru/for_developers/cpp/boost/conversion/ru/cast.shtml#numeric_cast"&gt;numeric_cast&lt;/a&gt;.&lt;/p&gt;&lt;p class="normal_text"&gt;Детальное обсуждение всех опций и вопросов, возникающих при форматировании строк, включая сравнение stringstream, lexical_cast, и других средств, можно найти в статье Херба Саттера (Herb Sutter) &lt;a href="http://www.gotw.ca/publications/mill19.htm"&gt;&amp;nbsp;&lt;i&gt;The String Formatters of Manor Farm&lt;/i&gt;&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;boost::lexical_cast позволяет снять эту проблему. Для его использования достаточно знать - какой тип в какой вы ходите преобразовать. И все. Например:&lt;/p&gt;&lt;pre&gt;// преобразует целое в строку
std::string str = boost::lexical_cast&amp;lt;std::string&amp;gt;(10);

// строку в целое
int value = boost::lexical_cast&amp;lt;int&amp;gt;(&amp;quot;10&amp;quot;);
// преобразует пару целых в экземпляр класса Point
Point pt = boost::lexical_cast&amp;lt;Point&amp;gt;(&amp;quot;10, 20&amp;quot;);

// обратное преобразование
std::wstring wstr = boost::lexical_cast&amp;lt;std::wstring&amp;gt;(pt);

// и т. д.
&lt;/pre&gt;&lt;p&gt;Достаточно удобно, не правда ли?&lt;/p&gt;&lt;h3&gt;Принципы работы.&lt;/h3&gt;&lt;div&gt;    &lt;p&gt;Принцип работы boost::lexical_cast очень прост. Для преобразования он использует строковый поток (std::strstream), выводя (с помощью оператора «) в него преобразуемое значние, после чего читая из него значение типа, в который делается преобразование. Т. е. вызов boost::lexical_cast эквивалентен:&lt;/p&gt;&lt;pre&gt;// положим, что from_val и to_val - это, соответственно преобразуемое

// значение и приемник результата преобразования
std::ostringstream o_str;
o_str &amp;lt;&amp;lt; from_val
std::istringstream i_str(o_str.str());
i_str &amp;gt;&amp;gt; to_val;
&lt;/pre&gt;&lt;p&gt;Из этого становится очевидным, что для корректного выполнения преобразования необходимо (и достаточно) наличия для преобразуемого типа перегруженного оператора вывода в поток и/или чтения из потока. Для всех примитивных типов такие операторы реализованы в библиотеке STL, а для «пользовательских» типов такой оператор может написать сам разработчик.&lt;/p&gt;&lt;h3&gt;Краткое описание&lt;/h3&gt;&lt;p&gt;Определенные в хидере "boost/lexical_cast.hpp" части библиотеки: &lt;/p&gt;&lt;pre&gt;namespace boost
{
    class bad_lexical_cast;
    template &amp;lt;typename Target, typename Source&amp;gt;
      Target lexical_cast(Source arg);
}
&lt;/pre&gt;&lt;p&gt;Тестовая программа - в файле lexical_cast_test.cpp.&lt;/p&gt;&lt;h3&gt;lexical_cast&lt;/h3&gt;&lt;pre&gt;template &amp;lt;typename Target, typename Source&amp;gt;
  Target lexical_cast(Source arg);
&lt;/pre&gt;&lt;p&gt;Функция возвращает результат передачи значение arg в стандартный строковый поток и обратного преобразования в объект типа Target. Когда тип Target это std::string или std::wstring, извлечение из потока получает полное содержимое строки, включая пробелы, вместо того, чтобы использовать operator&gt;&gt; по умолчанию. Если преобразование дает ошибку, то генерируется исключение  bad_lexical_cast. &lt;/p&gt;&lt;p&gt;Требования к аргументу и возвращаемому значению: &lt;/p&gt;&lt;p&gt;&lt;ul&gt;&lt;li&gt;Source является OutputStreamable, что значает, что определен operator&lt;&lt;, который получает объект типа std::ostream или std::wostream слева и объект типа аргумента справа. &lt;/li&gt;&lt;br /&gt;
&lt;li&gt;Target является InputStreamable, что означает, что определен operator&gt;&gt;, который берет объект типа std::istream или std::wistream слева (left hand side) и объект возвращаемого типа справа. &lt;/li&gt;&lt;br /&gt;
&lt;li&gt;Source и Target следуют парадигме CopyConstructible [20.1.3]. &lt;/li&gt;&lt;br /&gt;
&lt;li&gt;Target следует парадигме DefaultConstructible, что означает, что возможна инифиализация по умолчанию объекта этого типа [8.5, 20.1.4]. &lt;/li&gt;&lt;br /&gt;
&lt;/ul&gt;&lt;/p&gt;&lt;p&gt;Символьный тип используемого потока должен быть char, если только Source или Target не требуют использования потоков с wchar_t.  Типы Source, которые требую использования wchar_t-потоков это wchar_t, wchar_t *, и std::wstring. Типы Target, которые требуют использования wchar_t-потоков это wchar_t и std::wstring. &lt;/p&gt;&lt;p&gt;Если требуется более высокий уровень контроля за преобразованием, лучше использовать std::stringstream и std::wstringstream. Когда требуется выполнить преобразования без использования потоков, lexical_cast является неподходящим средством. &lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;h3&gt;bad_lexical_cast&lt;/h3&gt;&lt;pre&gt;class bad_lexical_cast : public std::bad_cast
{
{
public:
    ... // same member function interface as std::exception
};
&lt;/pre&gt;&lt;p&gt;Для сообщений об ошибках преобразования в lexical_cast используется генерация исключений.&lt;/p&gt;&lt;h3&gt;Недостатки&lt;/h3&gt;&lt;div&gt;    &lt;p&gt;Но не смотря на свою красоту, универсальность и соответствие общепринятым стандартам преобразования, у boost::lexical_cast есть и следущие недостатки:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Низкая скорость работы. По тестам, проведенным Гербом Саттером, результаты которых он описал в своих «Новых сложных задачах на С++», boost::lexical_cast работает на порядок медленнее, чем тот же sprintf.&lt;/li&gt;
&lt;li&gt;При преобразованиях нельзя специфицировать формат желаемой или исходной строки. Т. е. преобразования выполняются в соответствии со стандартными настройками потоков.&lt;/li&gt;
&lt;li&gt;(для компилятора Visual C++) нельзя (без дополнительных телодвижений) выполнять преобразования в std::wstring/wchar_t*, если в настройках проекта не указано, что wchar_t считается встроенным типом.&lt;/li&gt;
&lt;li&gt;приведение в тип double из строкового типа, возможно лишь в том случае если в качестве разделителя (дробной части от целой) используется точка.&lt;/li&gt;
&lt;/ul&gt;&lt;h3&gt;Достоинства&lt;/h3&gt;&lt;div&gt;    &lt;p&gt;Два из трех указанных выше недостатков достаточно легко обходятся. Поскольку boost::lexical_cast - это шаблон, то достаточно несложно написать необходимую специализацию, выполняющую преобразование настолько быстро, насколько это необходимо разработчику, а также учитывающую особенности типа wchar_t в VC++.&lt;/p&gt;&lt;h3&gt;Изменения&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Предыдущая версия шаблона lexical_cast использовала установки точности в потоках по умолчанию для чтения и записи чисел с плавающей запятой. Для числовых типов есть соответствующая специализация в std::numeric_limits, а текущая версия шаблона преобразования соответствующую точность. &lt;/li&gt;
&lt;li&gt;Предыдущая версия шаблона lexical_cast не поддерживала преобразование в или из типов на основе wchar_t. Для компиляторов, которые имеют полную поддержку для wchar_t, lexical_cast теперь поддерживает преобразование из wchar_t, wchar_t *, и std::wstring и в wchar_t и std::wstring. &lt;/li&gt;
&lt;li&gt;Предыдущая версия шаблона exical_cast основывалась на предположении, что обычные операторы извлечения из потока (stream extractor operators) достаточны для чтения значений. Однако,  строковый ввод/вывод  асимметричен, так как пробелы играют роль разделителей, а не входят в состав строк. Текущая версия исправляет эту ошибку для std::string и, где возможно, std::wstring: lexical_cast&amp;lt;std::string&amp;gt;("Hello, World") выполняется успешно вместо ошибки с генерацией исключения bad_lexical_cast.&lt;/li&gt;
&lt;li&gt;Предыдущая версия шаблона lexical_cast допускала небезопасное и бессмысленное преобразование к указателям. Текущая версия генерирует исключение bad_lexical_cast для преобразований в указатель:  lexical_cast&amp;lt;char*&amp;gt;("Goodbye, World") генерирует исключение вместо неопределенного поведения в предыдущей версии. &lt;/li&gt;
&lt;/ul&gt;&lt;h3&gt;Пример использования.&lt;/h3&gt;&lt;p&gt;Следующий пример преобразует аргументы командной строки в последовательность чисел:&lt;/p&gt;&lt;pre&gt;int main(int argc, char * argv[])
{
    using boost::lexical_cast;
    using boost::bad_lexical_cast;

    std::vector&amp;lt;short&amp;gt; args;

    while(*++argv)
    {
        try
        {
            args.push_back(lexical_cast&amp;lt;short&amp;gt;(*argv));
        }
        catch(bad_lexical_cast &amp;)
        {
            args.push_back(0);
        }
    }
    ...
}
&lt;/pre&gt;&lt;p&gt;Приведенный далее пример использует числовые величины в строковой выражении: &lt;/p&gt;&lt;pre&gt;void log_message(const std::string &amp;);

void log_errno(int yoko)
{
    log_message("Error " + boost::lexical_cast&amp;lt;std::string&amp;gt;(yoko) + ": " + strerror(yoko));
}
&lt;/pre&gt;&lt;p&gt;Приведенный далее пример переводит числовые величины в строковое представление: &lt;/p&gt;&lt;pre&gt;#include &amp;lt;string&amp;gt;
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;boost/lexical_cast.hpp&amp;gt;

int _tmain(int argc, _TCHAR* argv[])
{
    try {
        int a(41);
        std::string b;
        b = boost::lexical_cast&amp;lt;std::string&amp;gt;(a);
        std::cout &amp;lt;&amp;lt; b &amp;lt;&amp;lt; std::endl;
    }
    catch (const std::exception&amp; exc)
    {
        std::cout &amp;lt;&amp;lt; exc.what() &amp;lt;&amp;lt; std::endl;
    }
    return 0;
}
&lt;/pre&gt;&lt;p&gt;P.S.: Нагло спёрто отсюда &lt;a href="http://www.sources.ru/wiki/doku.php?id=doc:cpp:boost:lexical_cast"&gt;[[doc:cpp:boost:lexical_cast]]&lt;/a&gt; и отсюда &lt;a href="http://www.solarix.ru/for_developers/cpp/boost/conversion/ru/lexical_cast.shtml"&gt;библиотека преобразований - хидер boost/lexical_cast.hpp&lt;/a&gt;&lt;/p&gt;&lt;p&gt;P.P.S.: Об эффективности boost::lexical_cast&amp;lt;&amp;gt; можно прочитать здесь: &lt;a href="http://www.rsdn.ru/forum/flame.comp/2986431.flat.1.aspx"&gt;http://www.rsdn.ru/forum/flame.comp/2986431.flat.1.aspx&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1252038906587337119-7396483988769460065?l=rakafon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rakafon.blogspot.com/feeds/7396483988769460065/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://rakafon.blogspot.com/2009/04/boostlexicalcast.html#comment-form' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/7396483988769460065'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/7396483988769460065'/><link rel='alternate' type='text/html' href='http://rakafon.blogspot.com/2009/04/boostlexicalcast.html' title='Использование boost::lexical_cast'/><author><name>Rakafon</name><uri>http://www.blogger.com/profile/03386514126069055282</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-wnns05XIxW4/Ti7XTMmujOI/AAAAAAAAABg/rZpn54sM7BI/s1600/20168127'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1252038906587337119.post-4691992455468401529</id><published>2009-04-01T18:00:00.002+03:00</published><updated>2010-10-15T14:38:19.775+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='boost'/><category scheme='http://www.blogger.com/atom/ns#' term='cpp'/><title type='text'>Использование Boost.Regex</title><content type='html'>&lt;div class="content"&gt;В данной статье рассматриваются следующие вопросы касательно регулярных выражений:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;regex_match&lt;/li&gt;
&lt;li&gt;regex_search&lt;/li&gt;
&lt;li&gt;regex_replace&lt;/li&gt;
&lt;li&gt;regex_iterator&lt;/li&gt;
&lt;li&gt;regex_token_iterator&lt;/li&gt;
&lt;li&gt;Partial match&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Введение&lt;/h3&gt;&lt;br /&gt;
Я не хочу вступать в полемику по поводу нужности или не нужности регулярных выражений, каждый для себя решает сам. Моей целью было донести простоту использования Boost.Regex для тех, кому нравится использовать регулярные выражения. Для тех кому регулярные выражения не знакомы я советую прочесть хотя бы &lt;a href="http://ru.wikipedia.org/wiki/Регулярные_выражения"&gt;Википедию&lt;/a&gt;, а если кто-то хочет поглубже с ними познакомится, то я бы посоветовал &lt;a href="http://www.amazon.com/Mastering-Regular-Expressions-Jeffrey-Friedl/dp/0596528124/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1247388556&amp;sr=8-1"&gt;Mastering regular expressions&lt;/a&gt;. &lt;br /&gt;
Boost.Regex является собираемой библиотекой, т.е для ее использования необходимо ее собрать. Как это сделать написано в &lt;a href="http://www.boost.org/doc/libs/1_39_0/more/getting_started/index.html"&gt;Getting started&lt;/a&gt;.&lt;br /&gt;
Собирая библиотек вы можете выбрать один из двух алгоритмов, которые будет использоваться в движке регулирных выражений: рекурсивный и не-рекурсивный. Первый быстрый, но может грозить переполнением стека, второй немного медленней, но безопасный. Макросы для определения разных способов BOOST_REGEX_RECURSIVE и BOOST_REGEX_NON_RECURSIVE соответственно. Так же, каждый алгоритм может быть немного настроен. Макросы для настройки и их описание можно посмотреть &lt;a href="http://www.boost.org/doc/libs/1_39_0/libs/regex/doc/html/boost_regex/configuration/tuning.html"&gt;Здесь&lt;/a&gt;&lt;br /&gt;
Boost.Regex поддерживает следующие типы синтаксисов для регулярных выражений:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_39_0/libs/regex/doc/html/boost_regex/syntax/perl_syntax.html"&gt;Perl(по умолчанию)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_39_0/libs/regex/doc/html/boost_regex/syntax/basic_extended.html"&gt;POSIX Extended&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_39_0/libs/regex/doc/html/boost_regex/syntax/basic_syntax.html"&gt;POSIX Basic&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;br /&gt;
Необходимо учесть, что '.'(точка) по умолчанию включает в себя '\n'. Это может быть изменено передачей специального флага, в соответствующий алгоритм.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Основные алгоритмы&lt;/h3&gt;&lt;br /&gt;
&lt;h2&gt;&lt;a href="http://www.boost.org/doc/libs/1_39_0/libs/regex/doc/html/boost_regex/ref/regex_match.html"&gt;boost::regex_match&lt;/a&gt;&lt;/h2&gt;&lt;br /&gt;
Данный алгоритм используется для проверки соответсвия входящей строки и некоторого регулярного выражения, возвращая true Если строка соответсвует и false в другом случае. &lt;br /&gt;
Типичный способ использования: &lt;strong&gt;regex_match(входящая_строка, [результаты_нахождения_соответствий], регулярное_выражение, [флаги])&lt;/strong&gt;.&lt;br /&gt;
Полный список всех перегруженных объявлений смотри в документации.&lt;br /&gt;
Пример его использования:&lt;br /&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font color="black"&gt;std::&lt;font color="#0000ff"&gt;string&lt;/font&gt; xStr(&lt;font color="#A31515"&gt;&amp;quot;AAAA-12222-BBBBB-44455&amp;quot;&lt;/font&gt;);&lt;br /&gt;
boost::regex xRegEx(&lt;font color="#A31515"&gt;&amp;quot;(\\w+)-(\\d+)-(\\w+)-(\\d+)&amp;quot;&lt;/font&gt;);&lt;br /&gt;
boost::smatch xResults;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;==========================Results============================== \n&amp;quot;&lt;/font&gt;;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;Does this line match our needs? &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; std::boolalpha &amp;lt;&amp;lt; boost::regex_match(xStr,  xResults, xRegEx) &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;\n&amp;quot;&lt;/font&gt;; &lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;Print entire match:\n &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; xResults[0] &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;Print the former string into another format:\n&amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; xResults[1] &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;+&amp;quot;&lt;/font&gt;&lt;br /&gt;
&amp;lt;&amp;lt; xResults[2] &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;+&amp;quot;&lt;/font&gt;&lt;br /&gt;
&amp;lt;&amp;lt; xResults[3] &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;+&amp;quot;&lt;/font&gt;&lt;br /&gt;
&amp;lt;&amp;lt; xResults[4] &amp;lt;&amp;lt; std::endl;&lt;/font&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;font color="gray"&gt;* This source code was highlighted with &lt;a href="http://virtser.net/blog/post/source-code-highlighter.aspx"&gt;&lt;font color="gray"&gt;Source Code Highlighter&lt;/font&gt;&lt;/a&gt;.&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;
Результатом работы будет:&lt;br /&gt;
&lt;blockquote&gt;==========================Results==============================&lt;br /&gt;
Does this line match our needs? true&lt;br /&gt;
Print entire match:&lt;br /&gt;
AAAA-12222-BBBBB-44455&lt;br /&gt;
Print the former string into another format:&lt;br /&gt;
AAAA+12222+BBBBB+44455&lt;br /&gt;
&lt;/blockquote&gt;&lt;br /&gt;
&lt;h4&gt;Небольшое отступление от алгоритма, для описания его параметров. Эти параметры используются во всех алгоритмах, но рассмотрим их только здесь.&lt;/h4&gt;&lt;br /&gt;
&lt;strong&gt;результаты_нахождения_соответствий&lt;/strong&gt; — является опциональным параметром и есть ни что иное, как объект класса &lt;a href="http://www.boost.org/doc/libs/1_39_0/libs/regex/doc/html/boost_regex/ref/match_results.html"&gt;match_results&lt;/a&gt;. Этот объект является массивом объектов класса &lt;a href="http://www.boost.org/doc/libs/1_39_0/libs/regex/doc/html/boost_regex/ref/sub_match.html"&gt;sub_match&lt;/a&gt;, который в свою очередь, не более чем объект-хранитель итераторов на начало и конец найденного соответсвия в строке. &lt;strong&gt;результаты_нахождения_соответствий&lt;/strong&gt; служит для сохранения результатов работы алгоритма. Так, если алгоритм был выполнен успешно, то нулевой член массива будет хранить sub_match для всего найденного соответствия(исключение состовляет использование partial match, но об этом позже). Каждый последующий член массива будет хранить итераторы на каждый capture содержащийся в регулярном выражении. Каждый элемент массива может быть проверен на наличие контента через флаг matched. Важно помнить, что каждый sub_match хранит итераторы на &lt;strong&gt;входящую_строку&lt;/strong&gt;, поэтому нельзя передавать в качестве исходной строки временный объект и в дальнейшем использовать результаты алгоритма, в лучшем случае получите assert в дебаге, в худшем undefined behavior с головной болью. При рекурсивном capture в регулярном выражении(например &amp;quot;(\w)+&amp;quot;)) в результирующий match_result попадет только последний capture, это поведение по умолчание, которое можно изменить. Чтобы мы могли получить доступ ко всем рекурсивным capture, мы должны передать флаг match_extra в [флаги], но это еще не все, для того, чтобы match_extra сработал, необходим объявить дефайн BOOST_REGEX_MATCH_EXTRA во всех транслируемых юнитах. Или просто раскомментировать define в boost/regex/user.hpp. Это функциональность помечена как эксперементальная и сильно уменьшающая производительность. У меня так и не получилось ее опробовать, т.к моя VS2008 выдает Access violation в недрах xutulity при попытке использования алгоритмов regex_* с раскомментированным дефайном. Не протестированный пример ее использования:&lt;br /&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font color="black"&gt;std::&lt;font color="#0000ff"&gt;string&lt;/font&gt; xStr(&lt;font color="#A31515"&gt;&amp;quot;The boost library has a great opportunity for the regex!&amp;quot;&lt;/font&gt;);&lt;br /&gt;
boost::regex xRegEx(&lt;font color="#A31515"&gt;&amp;quot;(\\b\\w{5}\\b)*&amp;quot;&lt;/font&gt;);&lt;br /&gt;
boost::smatch xResults;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;==========================Results============================== \n&amp;quot;&lt;/font&gt;;   &lt;br /&gt;
&lt;font color="#0000ff"&gt;if&lt;/font&gt;( boost::regex_search(xStr, xResults, xRegEx, boost::match_extra) )&lt;br /&gt;
{ &lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;Words consist from exact 5 digits have been found in our line:\n&amp;quot;&lt;/font&gt;;&lt;br /&gt;
&lt;font color="#0000ff"&gt;for&lt;/font&gt;(&lt;font color="#0000ff"&gt;int&lt;/font&gt; j = 0; j &amp;lt; xResults.captures(1).size(); ++j)&lt;br /&gt;
std::cout &amp;lt;&amp;lt; xResults.captures(1)[j] &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
}&lt;/font&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;font color="gray"&gt;* This source code was highlighted with &lt;a href="http://virtser.net/blog/post/source-code-highlighter.aspx"&gt;&lt;font color="gray"&gt;Source Code Highlighter&lt;/font&gt;&lt;/a&gt;.&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;
&lt;strong&gt;[Флаги]&lt;/strong&gt; — необязательный параметр, с дефолтовым значением match_default. Про доступные флаги, можно посмотреть &lt;a href="http://www.boost.org/doc/libs/1_39_0/libs/regex/doc/html/boost_regex/ref/match_flag_type.html"&gt;здесь&lt;/a&gt;. Флаги комбинируются посредством '|'(or).&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;Partial match&lt;/h4&gt;&lt;br /&gt;
Частичное соответсвие необходимо для проверки входной строки, на частичное соответсвие регулярному выражению. Это может быть полезным при валидации поступающих асинхронно данных или при больших объемах данных, т.е в тех случаях когда в конкретный момент времени нет возможности провести полное соответсвие между регулярным выражением и исходной строкой. Чтобы использовать partial match, необходимо передать флаг match_partial в [флаги]. При этом, если используется частичное соответствие, то используемый алгоритм(regex_match, regex_search etc.) вернет true, но флаг matched у нулевого элеменат match_results будет уставновлен в false. То, что было найдено в результате частичного соответствия, можно получить через этот же нулевой элемент. &lt;br /&gt;
Пример использования:&lt;br /&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font color="black"&gt;std::&lt;font color="#0000ff"&gt;string&lt;/font&gt; xStr(&lt;font color="#A31515"&gt;&amp;quot;AAAA-12222&amp;quot;&lt;/font&gt;);&lt;br /&gt;
boost::regex xRegEx(&lt;font color="#A31515"&gt;&amp;quot;(\\w+)-(\\d+)-(\\w+)-(\\d+)&amp;quot;&lt;/font&gt;);&lt;br /&gt;
boost::smatch xResults;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;==========================Results============================== \n&amp;quot;&lt;/font&gt;;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;Does this line match the regex? &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; std::boolalpha &amp;lt;&amp;lt; boost::regex_match(xStr, xResults, xRegEx,&lt;br /&gt;
boost::match_default | boost::match_partial) &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;\n&amp;quot;&lt;/font&gt;; &lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;Is it the partial match? &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; std::boolalpha &amp;lt;&amp;lt;  !xResults[0].matched &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;\nPrint the partial match:\n&amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; xResults[0] &amp;lt;&amp;lt; std::endl;&lt;/font&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;font color="gray"&gt;* This source code was highlighted with &lt;a href="http://virtser.net/blog/post/source-code-highlighter.aspx"&gt;&lt;font color="gray"&gt;Source Code Highlighter&lt;/font&gt;&lt;/a&gt;.&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;
Вывод:&lt;br /&gt;
&lt;blockquote&gt;==========================Results==============================&lt;br /&gt;
Does this line match the regex? true&lt;br /&gt;
Is it the partial match? true&lt;br /&gt;
Print the partial match:&lt;br /&gt;
AAAA-12222&lt;br /&gt;
&lt;/blockquote&gt;&lt;br /&gt;
&lt;h2&gt;&lt;a href="http://www.boost.org/doc/libs/1_39_0/libs/regex/doc/html/boost_regex/ref/regex_search.html"&gt;regex_search&lt;/a&gt;&lt;/h2&gt;&lt;br /&gt;
Данный алгоритм предназначен для поиска подстроки в исходной строке, по заданному регулярному выражению.&lt;br /&gt;
Формат использования выглядит следующим образом:&lt;br /&gt;
&lt;strong&gt;regex_search(входящая_строка, [результаты_нахождения_соответствий], регулярное_выражение, [флаги])&lt;/strong&gt;.&lt;br /&gt;
Пример использования:&lt;br /&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font color="black"&gt;std::&lt;font color="#0000ff"&gt;string&lt;/font&gt; xStr(&lt;font color="#A31515"&gt;&amp;quot;The boost library has a great opportunity for the regex!&amp;quot;&lt;/font&gt;);&lt;br /&gt;
boost::regex xRegEx(&lt;font color="#A31515"&gt;&amp;quot;\\b(?:\\w+?)((\\w)\\2)(?:\\w+?)\\b&amp;quot;&lt;/font&gt;);&lt;br /&gt;
boost::smatch xResults;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;==========================Results============================== \n&amp;quot;&lt;/font&gt;;&lt;br /&gt;
std::&lt;font color="#0000ff"&gt;string&lt;/font&gt;::const_iterator xItStart = xStr.begin();&lt;br /&gt;
std::&lt;font color="#0000ff"&gt;string&lt;/font&gt;::const_iterator xItEnd = xStr.end();&lt;br /&gt;
&lt;font color="#0000ff"&gt;while&lt;/font&gt;( boost::regex_search(xItStart, xItEnd, xResults, xRegEx) )&lt;br /&gt;
{&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;Word, we've searched, is \&amp;quot;&amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; xResults[0] &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;\&amp;quot;. It has two \&amp;quot;&amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; xResults[2] &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;\&amp;quot; inside itself.\n&amp;quot;&lt;/font&gt;;&lt;br /&gt;
xItStart = xResults[1].second;&lt;br /&gt;
}&lt;/font&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;font color="gray"&gt;* This source code was highlighted with &lt;a href="http://virtser.net/blog/post/source-code-highlighter.aspx"&gt;&lt;font color="gray"&gt;Source Code Highlighter&lt;/font&gt;&lt;/a&gt;.&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;
Вывод:&lt;br /&gt;
&lt;blockquote&gt;==========================Results==============================&lt;br /&gt;
Word, we've searched, is «boost». It has two «o» inside itself.&lt;br /&gt;
Word, we've searched, is «opportunity». It has two «p» inside itself.&lt;/blockquote&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;&lt;a href="http://www.boost.org/doc/libs/1_39_0/libs/regex/doc/html/boost_regex/ref/regex_replace.html"&gt;regex_replace&lt;/a&gt;&lt;/h2&gt;&lt;br /&gt;
Алгоритм используется для замены всех вхождений подстрок, соответсвующих регулярному выражению, на строку заданному в определенном формате. Результат может быть получен через итератор, переданный в качестве аргумента либо как возращаемая строка. Части сроки которые не соответствуют регулярному выражению, копируются в выходнуб строку не измененными, если не задан флаг &lt;strong&gt;format_no_copy&lt;/strong&gt;, который оставляет только заматченные строки в результате. При переданном флаге format_first_only, заменяется только первая подстрока, соответствующая регулярному выражению.&lt;br /&gt;
Типично используемый формат:&lt;br /&gt;
&lt;strong&gt;regex_replace(входящая_строка, регулярное_выражение, форматная_строка, [флаги])&lt;/strong&gt;.&lt;br /&gt;
&lt;strong&gt;форматная_строка&lt;/strong&gt; определяет строку, на которую будет заменятся найденная подстрока.&lt;br /&gt;
Она может подчинятся одному из следующих правил синтаксиса:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_39_0/libs/regex/doc/html/boost_regex/format/sed_format.html"&gt;sed&lt;/a&gt; флаг:format_sed&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_39_0/libs/regex/doc/html/boost_regex/format/perl_format.html"&gt;Perl(по умолчанию)&lt;/a&gt; флаг:format_perl&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.boost.org/doc/libs/1_39_0/libs/regex/doc/html/boost_regex/format/boost_format_syntax.html"&gt;Boost-extended&lt;/a&gt; флаг:format_all&lt;/li&gt;
&lt;li&gt;Литеральный, т.е не использует никаких специальных символов. Флаг:format_literal&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Пример использования:&lt;br /&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font color="black"&gt;std::&lt;font color="#0000ff"&gt;string&lt;/font&gt; xStr(&lt;font color="#A31515"&gt;&amp;quot;AAAA-12222-BBBBB-44455&amp;quot;&lt;/font&gt;);&lt;br /&gt;
boost::regex xRegEx(&lt;font color="#A31515"&gt;&amp;quot;(\\w+)-(\\d+)-(\\w+)-(\\d+)&amp;quot;&lt;/font&gt;);&lt;br /&gt;
std::&lt;font color="#0000ff"&gt;string&lt;/font&gt; xFormatString(&lt;font color="#A31515"&gt;&amp;quot;$1*$2*$3*$4&amp;quot;&lt;/font&gt;);&lt;br /&gt;
boost::smatch xResults;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;==========================Results============================== \n&amp;quot;&lt;/font&gt;;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;Print string after replace:\n &amp;quot;&lt;/font&gt; &amp;lt;&amp;lt; boost::regex_replace(xStr, xRegEx, xFormatString, boost::match_default | boost::format_perl) &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
&lt;/font&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;font color="gray"&gt;* This source code was highlighted with &lt;a href="http://virtser.net/blog/post/source-code-highlighter.aspx"&gt;&lt;font color="gray"&gt;Source Code Highlighter&lt;/font&gt;&lt;/a&gt;.&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;
Вывод:&lt;br /&gt;
&lt;blockquote&gt;==========================Results==============================&lt;br /&gt;
Print string after replace:&lt;br /&gt;
AAAA*12222*BBBBB*44455&lt;br /&gt;
&lt;/blockquote&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Вспомогательные средства&lt;/h3&gt;&lt;br /&gt;
&lt;h2&gt;&lt;a href="http://www.boost.org/doc/libs/1_39_0/libs/regex/doc/html/boost_regex/ref/regex_iterator.html"&gt;regex_iterator&lt;/a&gt;&lt;/h2&gt;&lt;br /&gt;
Данный итератор может быть удобен для последовательного поиска вхождений подстроки, соответствующей регулярному выражению. При каждом инкрементировании находится следующая подстрока, с помощью regex_search. При разыменовывании итератора мы получаем объект типа match_results, с помощью которого мы можем получить всю необходимую информацию.&lt;br /&gt;
Формат использования: &lt;strong&gt;regex_iterator(начальный_итератор, конечный _итератор, регулярное_выражение)&lt;/strong&gt;&lt;br /&gt;
Пример использования:&lt;br /&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font color="black"&gt;std::&lt;font color="#0000ff"&gt;string&lt;/font&gt; xStr(&lt;font color="#A31515"&gt;&amp;quot;AAAA-12222-BBBBB-44455&amp;quot;&lt;/font&gt;);&lt;br /&gt;
boost::regex xRegEx(&lt;font color="#A31515"&gt;&amp;quot;(\\w|\\d)+&amp;quot;&lt;/font&gt;);&lt;br /&gt;
boost::smatch xResults;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;==========================Results============================== \n&amp;quot;&lt;/font&gt;;&lt;br /&gt;
boost::sregex_iterator xIt(xStr.begin(), xStr.end(), xRegEx);&lt;br /&gt;
boost::sregex_iterator xInvalidIt;&lt;br /&gt;
&lt;font color="#0000ff"&gt;while&lt;/font&gt;(xIt != xInvalidIt)&lt;br /&gt;
std::cout &amp;lt;&amp;lt; *xIt++ &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;*&amp;quot;&lt;/font&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;font color="gray"&gt;* This source code was highlighted with &lt;a href="http://virtser.net/blog/post/source-code-highlighter.aspx"&gt;&lt;font color="gray"&gt;Source Code Highlighter&lt;/font&gt;&lt;/a&gt;.&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;
Вывод:&lt;br /&gt;
&lt;blockquote&gt;==========================Results==============================&lt;br /&gt;
AAAA*12222*BBBBB*44455*&lt;/blockquote&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;&lt;a href="http://www.boost.org/doc/libs/1_39_0/libs/regex/doc/html/boost_regex/ref/regex_token_iterator.html"&gt;regex_token_iterator&lt;/a&gt;&lt;/h2&gt;&lt;br /&gt;
Очень полезный интрумент для разбиаения строки на токены,&lt;br /&gt;
Формат использования: regex_token_iterator(начальный_итератор, конечный _итератор, регулярное_выражение, [submatch])&lt;br /&gt;
&lt;strong&gt;[submatch]&lt;/strong&gt; используется для указания, как следует интерпретировать токены в строке.&lt;br /&gt;
При -1 итератор возвращает часть последовательности, которая не соответствует регулярному выражению. Т.е возвращается либо строка, которая идет после первого совпадения, до начала следующего совпадения(не включая первый символ совпадения). Либо, с начала строки, если начала строки не удовлетворяет регулярному выражению. Т.е при передаче -1, регулярное выражения является разделителем. При 0, каждое смещение итератора(++) дает следующую часть строки которая была “заматчена“, т.е каждый разыменованный итератор является capture строки. При любом положительном числе, в качестве параметра, выбирается capture регулярного выражения соответствующий числу, переданному в качестве параметра. Так же можно передать массив индексов в качестве параметра, тогда итератор будет искать каждый capture согласно индексам в массиве, т.е если массив состоит из {4, 2, 1}, тогда начальный итератор будет указывать на 4 capture, следующий итератор на 2 и т.д. Процесс будет повторятся для всей последовательности, пока не закончатся соответствия для данного регулярного выражения. По дефолту это параметр равен 0.&lt;br /&gt;
Разыменованный итератор является объектом класса sub_match.&lt;br /&gt;
Примеры использования:&lt;br /&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font color="black"&gt;std::&lt;font color="#0000ff"&gt;string&lt;/font&gt; xStr(&lt;font color="#A31515"&gt;&amp;quot;AAAA-12222-BBBBB-44455&amp;quot;&lt;/font&gt;);&lt;br /&gt;
boost::regex xRegEx(&lt;font color="#A31515"&gt;&amp;quot;(\\w|\\d)+&amp;quot;&lt;/font&gt;);&lt;br /&gt;
boost::smatch xResults;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;==========================Results============================== \n&amp;quot;&lt;/font&gt;;&lt;br /&gt;
boost::sregex_token_iterator xItFull(xStr.begin(), xStr.end(), xRegEx, 0);&lt;br /&gt;
boost::sregex_token_iterator xInvalidIt;&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;Result the same as the regex_iterator: \n&amp;quot;&lt;/font&gt;;&lt;br /&gt;
&lt;font color="#0000ff"&gt;while&lt;/font&gt;(xItFull != xInvalidIt)&lt;br /&gt;
std::cout &amp;lt;&amp;lt; *xItFull++ &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;*&amp;quot;&lt;/font&gt;;&lt;br /&gt;
&lt;font color="#008000"&gt;//Parts of captures&lt;/font&gt;&lt;br /&gt;
boost::regex xRegEx2(&lt;font color="#A31515"&gt;&amp;quot;(\\w+)-(\\d+)&amp;quot;&lt;/font&gt;);&lt;br /&gt;
boost::sregex_token_iterator xItFirstCapture(xStr.begin(), xStr.end(), xRegEx2, 1);&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;\nShow only first captures: \n&amp;quot;&lt;/font&gt;;&lt;br /&gt;
&lt;font color="#0000ff"&gt;while&lt;/font&gt;(xItFirstCapture != xInvalidIt)&lt;br /&gt;
std::cout &amp;lt;&amp;lt; *xItFirstCapture++ &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;*&amp;quot;&lt;/font&gt;;&lt;br /&gt;
&lt;font color="#008000"&gt;//Reverse order&lt;/font&gt;&lt;br /&gt;
&lt;font color="#0000ff"&gt;int&lt;/font&gt; aIndices[] = {2,1};&lt;br /&gt;
boost::sregex_token_iterator xItReverseCapture(xStr.begin(), xStr.end(), xRegEx2, aIndices);&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;\nShow captures in the reverse order: \n&amp;quot;&lt;/font&gt;;&lt;br /&gt;
&lt;font color="#0000ff"&gt;while&lt;/font&gt;(xItReverseCapture != xInvalidIt)&lt;br /&gt;
std::cout &amp;lt;&amp;lt; *xItReverseCapture++ &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;*&amp;quot;&lt;/font&gt;;&lt;br /&gt;
&lt;font color="#008000"&gt;//Delimiters&lt;/font&gt;&lt;br /&gt;
boost::regex xRegEx3(&lt;font color="#A31515"&gt;&amp;quot;(\\w|\\d)+&amp;quot;&lt;/font&gt;);&lt;br /&gt;
boost::sregex_token_iterator xItDelimiters(xStr.begin(), xStr.end(), xRegEx3, -1);&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot;\nShow delimiters: \n&amp;quot;&lt;/font&gt;;&lt;br /&gt;
&lt;font color="#0000ff"&gt;while&lt;/font&gt;(xItDelimiters != xInvalidIt)&lt;br /&gt;
std::cout &amp;lt;&amp;lt; *xItDelimiters++ &amp;lt;&amp;lt; &lt;font color="#A31515"&gt;&amp;quot; &amp;quot;&lt;/font&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;font color="gray"&gt;* This source code was highlighted with &lt;a href="http://virtser.net/blog/post/source-code-highlighter.aspx"&gt;&lt;font color="gray"&gt;Source Code Highlighter&lt;/font&gt;&lt;/a&gt;.&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;
Вывод:&lt;br /&gt;
&lt;blockquote&gt;==========================Results==============================&lt;br /&gt;
Result the same as the regex_iterator:&lt;br /&gt;
AAAA*12222*BBBBB*44455*&lt;br /&gt;
Show only first captures:&lt;br /&gt;
AAAA*BBBBB*&lt;br /&gt;
Show captures in the reverse order:&lt;br /&gt;
12222*AAAA*44455*BBBBB*&lt;br /&gt;
Show delimiters:&lt;br /&gt;
—  — -&lt;/blockquote&gt;&lt;br /&gt;
&lt;h3&gt;Замечание&lt;/h3&gt;&lt;br /&gt;
Любой алгоритм может выбросить исключение типа std::runtime_error в случае если сложность проверки полного соответствия(matching) N элементов начнет превышать О(N^2) или в случае переполнения стека(если Boost.Regex был собран в рекурсивном режиме)&lt;br /&gt;
&lt;br /&gt;
_________&lt;br /&gt;
&lt;/div&gt;&lt;p&gt;P.S.: ... наглым и безобразным образом утянуто отсюда: &lt;a href="http://habrahabr.ru/blogs/cpp/64226/"&gt; Boost это просто. Часть 1. Boost.Regex&lt;/a&gt;&lt;/p&gt;&lt;p&gt;P.S.: ... также о boost::regex можно прочитать здесь: &lt;a href="http://www.solarix.ru/for_developers/cpp/boost/regex/ru/index.shtml"&gt;BOOST C++: библиотека Regex - регулярные выражения&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1252038906587337119-4691992455468401529?l=rakafon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rakafon.blogspot.com/feeds/4691992455468401529/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://rakafon.blogspot.com/2009/04/boostregex.html#comment-form' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/4691992455468401529'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/4691992455468401529'/><link rel='alternate' type='text/html' href='http://rakafon.blogspot.com/2009/04/boostregex.html' title='Использование Boost.Regex'/><author><name>Rakafon</name><uri>http://www.blogger.com/profile/03386514126069055282</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-wnns05XIxW4/Ti7XTMmujOI/AAAAAAAAABg/rZpn54sM7BI/s1600/20168127'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1252038906587337119.post-3528953648700444914</id><published>2009-04-01T16:00:00.002+03:00</published><updated>2010-10-15T14:38:33.988+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cpplib'/><category scheme='http://www.blogger.com/atom/ns#' term='cpp'/><title type='text'>Сборка библиотеки LibTorrent</title><content type='html'>&lt;ul&gt;&lt;li&gt;Скачать либу &lt;a href="http://sourceforge.net/projects/libtorrent/"&gt;здесь&lt;/a&gt; или &lt;a href="http://mirsofta.ru/pod.php?prog=1228619299"&gt;здесь&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Уже должны быть собраны &lt;a href="http://rakafon.blogspot.com/2009/04/boost-boost-c.html"&gt;Boost&lt;/a&gt; и &lt;a href="http://rakafon.blogspot.com/2009/04/openssl.html"&gt;OpenSSL&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;прочитайте прежде статью: &lt;a href="http://rakafon.blogspot.com/2009/04/o-acpo-eeoea-install-microsoft-visual.html"&gt;Development Environment Settings&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Сборка с помощью Visual Studio 2005&lt;/p&gt;&lt;pre style="border: 1px solid gray; margin: 5px 20px; padding: 10px; background-color: rgb(220, 220, 220);"&gt;cd &amp;quot;%LIBRARIES_ROOT%libtorrent&amp;quot;

set INCLUDE=%BOOST_ROOT%;%LIBRARIES_ROOT%\libtorrent;%LIBRARIES_ROOT%\openssl\include;
CALL &amp;quot;C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\VSVARS32.BAT&amp;quot;
%LIBRARIES_ROOT%boost-jam-3.1.17\bin.ntx86\bjam --v2 toolset=msvc-8.0 link=static debug logging=none dht-support=on runtime-link=static asynch-exceptions=on character-set=unicode openssl=pe

set INCLUDE=%BOOST_ROOT%;%LIBRARIES_ROOT%\libtorrent;%LIBRARIES_ROOT%\openssl\include;
CALL &amp;quot;C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\VSVARS32.BAT&amp;quot;
%LIBRARIES_ROOT%boost-jam-3.1.17\bin.ntx86\bjam --v2 toolset=msvc-8.0 link=static release logging=none dht-support=on runtime-link=static asynch-exceptions=on character-set=unicode openssl=pe

set INCLUDE=%BOOST_ROOT%;%LIBRARIES_ROOT%\libtorrent;%LIBRARIES_ROOT%\openssl\include;
CALL &amp;quot;C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\VSVARS32.BAT&amp;quot;
%LIBRARIES_ROOT%boost-jam-3.1.17\bin.ntx86\bjam --v2 toolset=msvc-8.0 link=static debug logging=none dht-support=on runtime-link=static asynch-exceptions=off character-set=unicode openssl=pe

set INCLUDE=%BOOST_ROOT%;%LIBRARIES_ROOT%\libtorrent;%LIBRARIES_ROOT%\openssl\include;
CALL &amp;quot;C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\VSVARS32.BAT&amp;quot;
%LIBRARIES_ROOT%boost-jam-3.1.17\bin.ntx86\bjam --v2 toolset=msvc-8.0 link=static release logging=none dht-support=on runtime-link=static asynch-exceptions=off character-set=unicode openssl=pe

set INCLUDE=%BOOST_ROOT%;%LIBRARIES_ROOT%\libtorrent;%LIBRARIES_ROOT%\openssl\include;
CALL &amp;quot;C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\VSVARS32.BAT&amp;quot;
%LIBRARIES_ROOT%boost-jam-3.1.17\bin.ntx86\bjam --v2 toolset=msvc-8.0 link=static debug logging=none dht-support=on runtime-link=shared asynch-exceptions=on character-set=unicode openssl=pe

set INCLUDE=%BOOST_ROOT%;%LIBRARIES_ROOT%\libtorrent;%LIBRARIES_ROOT%\openssl\include;
CALL &amp;quot;C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\VSVARS32.BAT&amp;quot;
%LIBRARIES_ROOT%boost-jam-3.1.17\bin.ntx86\bjam --v2 toolset=msvc-8.0 link=static release logging=none dht-support=on runtime-link=shared asynch-exceptions=on character-set=unicode openssl=pe

set INCLUDE=%BOOST_ROOT%;%LIBRARIES_ROOT%\libtorrent;%LIBRARIES_ROOT%\openssl\include;
CALL &amp;quot;C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\VSVARS32.BAT&amp;quot;
%LIBRARIES_ROOT%boost-jam-3.1.17\bin.ntx86\bjam --v2 toolset=msvc-8.0 link=static debug logging=none dht-support=on runtime-link=shared asynch-exceptions=off character-set=unicode openssl=pe

set INCLUDE=%BOOST_ROOT%;%LIBRARIES_ROOT%\libtorrent;%LIBRARIES_ROOT%\openssl\include;
CALL &amp;quot;C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\VSVARS32.BAT&amp;quot;
%LIBRARIES_ROOT%boost-jam-3.1.17\bin.ntx86\bjam --v2 toolset=msvc-8.0 link=static release logging=none dht-support=on runtime-link=shared asynch-exceptions=off character-set=unicode openssl=pe
&lt;/pre&gt;&lt;br /&gt;
Сборка с помощью Visual Studio 2008 &lt;pre style="border: 1px solid gray; margin: 5px 20px; padding: 10px; background-color: rgb(220, 220, 220);"&gt;set INCLUDE=%BOOST_ROOT%;%LIBRARIES_ROOT%\libtorrent;%LIBRARIES_ROOT%\openssl\include;
CALL &amp;quot;C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\VSVARS32.BAT&amp;quot;
%LIBRARIES_ROOT%boost-jam-3.1.17\bin.ntx86\bjam --v2 toolset=msvc-9.0 link=static debug logging=none dht-support=on runtime-link=static asynch-exceptions=on character-set=unicode openssl=pe

set INCLUDE=%BOOST_ROOT%;%LIBRARIES_ROOT%\libtorrent;%LIBRARIES_ROOT%\openssl\include;
CALL &amp;quot;C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\VSVARS32.BAT&amp;quot;
%LIBRARIES_ROOT%boost-jam-3.1.17\bin.ntx86\bjam --v2 toolset=msvc-9.0 link=static release logging=none dht-support=on runtime-link=static asynch-exceptions=on character-set=unicode openssl=pe

set INCLUDE=%BOOST_ROOT%;%LIBRARIES_ROOT%\libtorrent;%LIBRARIES_ROOT%\openssl\include;
CALL &amp;quot;C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\VSVARS32.BAT&amp;quot;
%LIBRARIES_ROOT%boost-jam-3.1.17\bin.ntx86\bjam --v2 toolset=msvc-9.0 link=static debug logging=none dht-support=on runtime-link=static asynch-exceptions=off character-set=unicode openssl=pe

set INCLUDE=%BOOST_ROOT%;%LIBRARIES_ROOT%\libtorrent;%LIBRARIES_ROOT%\openssl\include;
CALL &amp;quot;C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\VSVARS32.BAT&amp;quot;
%LIBRARIES_ROOT%boost-jam-3.1.17\bin.ntx86\bjam --v2 toolset=msvc-9.0 link=static release logging=none dht-support=on runtime-link=static asynch-exceptions=off character-set=unicode openssl=pe

set INCLUDE=%BOOST_ROOT%;%LIBRARIES_ROOT%\libtorrent;%LIBRARIES_ROOT%\openssl\include;
CALL &amp;quot;C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\VSVARS32.BAT&amp;quot;
%LIBRARIES_ROOT%boost-jam-3.1.17\bin.ntx86\bjam --v2 toolset=msvc-9.0 link=static debug logging=none dht-support=on runtime-link=shared asynch-exceptions=on character-set=unicode openssl=pe

set INCLUDE=%BOOST_ROOT%;%LIBRARIES_ROOT%\libtorrent;%LIBRARIES_ROOT%\openssl\include;
CALL &amp;quot;C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\VSVARS32.BAT&amp;quot;
%LIBRARIES_ROOT%boost-jam-3.1.17\bin.ntx86\bjam --v2 toolset=msvc-9.0 link=static release logging=none dht-support=on runtime-link=shared asynch-exceptions=on character-set=unicode openssl=pe

set INCLUDE=%BOOST_ROOT%;%LIBRARIES_ROOT%\libtorrent;%LIBRARIES_ROOT%\openssl\include;
CALL &amp;quot;C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\VSVARS32.BAT&amp;quot;
%LIBRARIES_ROOT%boost-jam-3.1.17\bin.ntx86\bjam --v2 toolset=msvc-9.0 link=static debug logging=none dht-support=on runtime-link=shared asynch-exceptions=off character-set=unicode openssl=pe

set INCLUDE=%BOOST_ROOT%;%LIBRARIES_ROOT%\libtorrent;%LIBRARIES_ROOT%\openssl\include;
CALL &amp;quot;C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\VSVARS32.BAT&amp;quot;
%LIBRARIES_ROOT%boost-jam-3.1.17\bin.ntx86\bjam --v2 toolset=msvc-9.0 link=static release logging=none dht-support=on runtime-link=shared asynch-exceptions=off character-set=unicode openssl=pe
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
P.S.: Смотри также:&lt;br /&gt;
&lt;a href="http://www.rsdn.ru/forum/network/3404574.flat.aspx#3404574"&gt;http://www.rsdn.ru/forum/network/3404574.flat.aspx#3404574&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://www.rsdn.ru/forum/dotnet/3404592.flat.aspx#3404592"&gt;http://www.rsdn.ru/forum/dotnet/3404592.flat.aspx#3404592&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1252038906587337119-3528953648700444914?l=rakafon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rakafon.blogspot.com/feeds/3528953648700444914/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://rakafon.blogspot.com/2009/04/libtorrent.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/3528953648700444914'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/3528953648700444914'/><link rel='alternate' type='text/html' href='http://rakafon.blogspot.com/2009/04/libtorrent.html' title='Сборка библиотеки LibTorrent'/><author><name>Rakafon</name><uri>http://www.blogger.com/profile/03386514126069055282</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-wnns05XIxW4/Ti7XTMmujOI/AAAAAAAAABg/rZpn54sM7BI/s1600/20168127'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1252038906587337119.post-5542037742200778609</id><published>2009-04-01T15:00:00.001+03:00</published><updated>2010-10-15T14:38:38.538+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cpplib'/><category scheme='http://www.blogger.com/atom/ns#' term='cpp'/><title type='text'>Сборка библиотеки OpenSSL</title><content type='html'>&lt;ul&gt;&lt;li&gt;Скачать либу здесь : &lt;a href="http://www.openssl.org/source/openssl-0.9.8j.tar.gz"&gt;openssl-0.9.8j.tar.gz&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Скачать Active Perl отсюда: &lt;a href="http://www.softportal.com/get-70-activeperl.html"&gt;http://www.softportal.com/get-70-activeperl.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Установить Active Perl&lt;/li&gt;
&lt;/ul&gt;Сборка с помощью Visual Studio 2005: &lt;pre style="border: 1px solid gray; margin: 5px 20px; padding: 10px; background-color: rgb(220, 220, 220);"&gt;set OPTS=no-asm

perl Configure VC-WIN32
perl util\mkfiles.pl &amp;gt;MINFO
perl util\mk1mf.pl %OPTS% debug VC-WIN32 &amp;gt;d32.mak
perl util\mk1mf.pl %OPTS% VC-WIN32 &amp;gt;32.mak
perl util\mk1mf.pl %OPTS% debug dll VC-WIN32 &amp;gt;d32dll.mak
perl util\mk1mf.pl %OPTS% dll VC-WIN32 &amp;gt;32dll.mak
perl util\mkdef.pl 32 libeay &amp;gt; ms\libeay32.def
perl util\mkdef.pl 32 ssleay &amp;gt; ms\ssleay32.def

rem set PATH=%MSSDK6DIR%\VC\Bin;%PATH%
call &amp;quot;c:\Program Files\Microsoft Visual Studio 8\Common7\Tools\vsvars32.bat&amp;quot;

nmake -f d32.mak
@if errorlevel 1 goto end
nmake -f 32.mak
@if errorlevel 1 goto end
nmake -f d32dll.mak
@if errorlevel 1 goto end
nmake -f 32dll.mak

:end
&lt;/pre&gt;&lt;br /&gt;
Сборка с помощью Visual Studio 2008: &lt;pre style="border: 1px solid gray; margin: 5px 20px; padding: 10px; background-color: rgb(220, 220, 220);"&gt;set OPTS=no-asm

perl Configure VC-WIN32
perl util\mkfiles.pl &amp;gt;MINFO
perl util\mk1mf.pl %OPTS% debug VC-WIN32 &amp;gt;d32.mak
perl util\mk1mf.pl %OPTS% VC-WIN32 &amp;gt;32.mak
perl util\mk1mf.pl %OPTS% debug dll VC-WIN32 &amp;gt;d32dll.mak
perl util\mk1mf.pl %OPTS% dll VC-WIN32 &amp;gt;32dll.mak
perl util\mkdef.pl 32 libeay &amp;gt; ms\libeay32.def
perl util\mkdef.pl 32 ssleay &amp;gt; ms\ssleay32.def

rem set PATH=%MSSDK6DIR%\VC\Bin;%PATH%
call &amp;quot;c:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\vsvars32.bat&amp;quot;

nmake -f d32.mak
@if errorlevel 1 goto end
nmake -f 32.mak
@if errorlevel 1 goto end
nmake -f d32dll.mak
@if errorlevel 1 goto end
nmake -f 32dll.mak

:end
&lt;/pre&gt;&lt;br /&gt;
Сборка с помощью Vista SDK &lt;pre style="border: 1px solid gray; margin: 5px 20px; padding: 10px; background-color: rgb(220, 220, 220);"&gt;set OPTS=no-asm

perl Configure VC-WIN32
perl util\mkfiles.pl &amp;gt;MINFO
perl util\mk1mf.pl %OPTS% debug VC-WIN32 &amp;gt;d32.mak
perl util\mk1mf.pl %OPTS% VC-WIN32 &amp;gt;32.mak
perl util\mk1mf.pl %OPTS% debug dll VC-WIN32 &amp;gt;d32dll.mak
perl util\mk1mf.pl %OPTS% dll VC-WIN32 &amp;gt;32dll.mak
perl util\mkdef.pl 32 libeay &amp;gt; ms\libeay32.def
perl util\mkdef.pl 32 ssleay &amp;gt; ms\ssleay32.def

@SET VSINSTALLDIR=c:\Program Files\Microsoft Visual Studio 8
@SET VCINSTALLDIR=%VSINSTALLDIR%\VC
@SET FrameworkDir=c:\WINDOWS\Microsoft.NET\Framework
@SET FrameworkVersion=v2.0.50727
@SET FrameworkSDKDir=%VSINSTALLDIR%\SDK\v2.0
@set DevEnvDir=%VSINSTALLDIR%\Common7\IDE
@set PATH=%MSSDK6DIR%\VC\Bin;%VSINSTALLDIR%\Common7\IDE;%VCINSTALLDIR%\BIN;%VSINSTALLDIR%\Common7\Tools;%VSINSTALLDIR%\Common7\Tools\bin;%VCINSTALLDIR%\PlatformSDK\bin;%VSINSTALLDIR%\SDK\v2.0\bin;c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727;%VCINSTALLDIR%\VCPackages;%PATH%
@set INCLUDE=%MSSDK6DIR%\Include;%MSSDK6DIR%\VC\INCLUDE;%VCINSTALLDIR%\ATLMFC\INCLUDE;%VCINSTALLDIR%\INCLUDE;%VCINSTALLDIR%\PlatformSDK\include;%VSINSTALLDIR%\SDK\v2.0\include;%INCLUDE%
@set LIB=%MSSDK6DIR%\Lib;%MSSDK6DIR%\VC\LIB;%VCINSTALLDIR%\ATLMFC\LIB;%VCINSTALLDIR%\LIB;%VCINSTALLDIR%\PlatformSDK\lib;%VSINSTALLDIR%\SDK\v2.0\lib;%LIB%
@set LIBPATH=c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727;%VCINSTALLDIR%\ATLMFC\LIB

nmake -f d32.mak
@if errorlevel 1 goto end
nmake -f 32.mak
@if errorlevel 1 goto end
nmake -f d32dll.mak
@if errorlevel 1 goto end
nmake -f 32dll.mak

:end
&lt;/pre&gt;&lt;br /&gt;
Скрипт для инсталла: &lt;pre style="border: 1px solid gray; margin: 5px 20px; padding: 10px; background-color: rgb(220, 220, 220);"&gt;set OPENSSL_ROOT=%~dp0
set TOOLSET=%1%

cd %OPENSSL_ROOT%
call :CreateDirectories
call :MoveOutFiles
call :RemoveOldDirectories
goto end

:CreateDirectories
mkdir lib
cd ./lib
mkdir %TOOLSET%
cd ./%TOOLSET%
mkdir debug
cd ./debug
mkdir shared
mkdir static
cd ..
mkdir release
cd ./release
mkdir shared
mkdir static
cd ..
exit /b

:MoveOutFiles
cd %OPENSSL_ROOT%
move %OPENSSL_ROOT%out32\* %OPENSSL_ROOT%lib\%TOOLSET%\release\static\
move %OPENSSL_ROOT%out32dll\* %OPENSSL_ROOT%lib\%TOOLSET%\release\shared\
move %OPENSSL_ROOT%out32.dbg\* %OPENSSL_ROOT%lib\%TOOLSET%\debug\static\
move %OPENSSL_ROOT%out32dll.dbg\* %OPENSSL_ROOT%lib\%TOOLSET%\debug\shared\
cd %OPENSSL_ROOT%
exit /b

:RemoveOldDirectories
del /S /Q %OPENSSL_ROOT%out32\*
del /S /Q %OPENSSL_ROOT%out32dll\*
del /S /Q %OPENSSL_ROOT%out32.dbg\*
del /S /Q %OPENSSL_ROOT%out32dll.dbg\*
del /S /Q %OPENSSL_ROOT%out32
del /S /Q %OPENSSL_ROOT%out32dll
del /S /Q %OPENSSL_ROOT%out32.dbg
del /S /Q %OPENSSL_ROOT%out32dll.dbg
del /S /Q %OPENSSL_ROOT%tmp32\*
del /S /Q %OPENSSL_ROOT%tmp32dll\*
del /S /Q %OPENSSL_ROOT%tmp32.dbg\*
del /S /Q %OPENSSL_ROOT%tmp32dll.dbg\*
del /S /Q %OPENSSL_ROOT%tmp32
del /S /Q %OPENSSL_ROOT%tmp32dll
del /S /Q %OPENSSL_ROOT%tmp32.dbg
del /S /Q %OPENSSL_ROOT%tmp32dll.dbg
exit /b

:end
&lt;/pre&gt;&lt;br /&gt;
&lt;p&gt;P.S.: Возможно после конфигурации придётся слегуа поправить make-файлы, поскольку собирают они библиотеку не во всех возможных конфигурациях. Например когда собирается статическая версия OpenSSL, то с С++ CRT она линкуется статически, если же собирается динамическая версия OpenSSL, то она с С++ библиотекой линкуется динамически. Скажем если вы хотите собрать статическую версию OpenSSL, а запользовать её в проекте, линкующимся с CRT динамически, вот тогда и придётся править фалики.&lt;/p&gt;&lt;br /&gt;
&lt;p&gt;Смотри также: &lt;a href="http://www.ski-epic.com/2007_notes_on_openssl/index.html"&gt;Compiling OpenSSL for Windows, Linux, and Macintosh&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1252038906587337119-5542037742200778609?l=rakafon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rakafon.blogspot.com/feeds/5542037742200778609/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://rakafon.blogspot.com/2009/04/openssl.html#comment-form' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/5542037742200778609'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/5542037742200778609'/><link rel='alternate' type='text/html' href='http://rakafon.blogspot.com/2009/04/openssl.html' title='Сборка библиотеки OpenSSL'/><author><name>Rakafon</name><uri>http://www.blogger.com/profile/03386514126069055282</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-wnns05XIxW4/Ti7XTMmujOI/AAAAAAAAABg/rZpn54sM7BI/s1600/20168127'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1252038906587337119.post-1471411177289337474</id><published>2009-04-01T14:00:00.004+03:00</published><updated>2010-10-15T14:38:50.220+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cpplib'/><category scheme='http://www.blogger.com/atom/ns#' term='boost'/><category scheme='http://www.blogger.com/atom/ns#' term='cpp'/><title type='text'>Библиотека Boost</title><content type='html'>&lt;p&gt;&lt;b&gt;&lt;a href="http://ru.wikipedia.org/wiki/Boost_%28%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B0%29"&gt;Boost&lt;/a&gt;&lt;/b&gt; — &lt;a href="http://www.boost.org/doc/libs/1_39_0/libs/libraries.htm"&gt;собрание библиотек&lt;/a&gt;, расширяющих &lt;a href="http://ru.wikipedia.org/wiki/C%2B%2B" title="C++"&gt;C++&lt;/a&gt;. Cвободно распространяются по лицензии &lt;a href="http://www.boost.org/more/license_info.html" class="external text" title="http://www.boost.org/more/license_info.html" rel="nofollow"&gt;Boost Software License&lt;/a&gt; вместе с исходным кодом. Проект был создан после принятия стандарта &lt;a href="http://ru.wikipedia.org/wiki/C%2B%2B" title="C++"&gt;C++&lt;/a&gt;, когда многие были недовольны не включением в стандарт некоторых библиотек. Проект является своего рода «испытательным полигоном» для различных расширений языка и &lt;a href="http://www.open-std.org/jtc1/sc22/wg21/docs/library_technical_report.html" class="external text" title="http://www.open-std.org/jtc1/sc22/wg21/docs/library_technical_report.html" rel="nofollow"&gt;часть библиотек&lt;/a&gt; являются кандидатами на включение в следующий стандарт &lt;a href="http://ru.wikipedia.org/wiki/C%2B%2B" title="C++"&gt;C++&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Boost&lt;/b&gt; имеет заметную направленность на исследования и расширяемость (&lt;a href="http://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5" title="Метапрограммирование"&gt;метапрограммирование&lt;/a&gt; и &lt;a href="http://ru.wikipedia.org/wiki/%D0%9E%D0%B1%D0%BE%D0%B1%D1%89%D1%91%D0%BD%D0%BD%D0%BE%D0%B5_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5" title="Обобщённое программирование"&gt;обобщённое программирование&lt;/a&gt; с активным использованием &lt;a href="http://ru.wikipedia.org/wiki/%D0%A8%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D1%8B_C%2B%2B" title="Шаблоны C++"&gt;шаблонов&lt;/a&gt;). Благодаря тщательному подбору и контролю качества, библиотеки, включённые в Boost, обладают высокой надёжностью и производительностью. У &amp;quot;велосипедов&amp;quot; из boost существует огромное количество пользователей - С++ разработчиков, поэтому код библиотек boost является очень хорошо протестирован и является очень надёжным.&lt;/p&gt;&lt;p&gt;Крайне рекомендую данную коллекцию библиотек всем C++ разработчикам для использования в своих проектах. Вместо написания собственных велосипедов, лучше загляните в boost, не присутствует ли там уже готовое решение, поскольку качество вашего велосипеда будет насравнимо ниже чем boost'овского аналога, потому что пользователем вашего вилосипеда будете только вы и оттестировать его во всех возможных случаях вы не сможете физически. Если вас не совсем устроит эффективность некоторых библиотек из boost (как например boost::lexical_cast), то не забывайте, что библиотеки boost чрезвычайно гибки и вы всегда можете расширить функциональность того или иного велосипеда с помощью C++ шаблонов (скажем, специализировать шаблон boost::lexical_cast&amp;lt;&amp;gt; для определённого типа), предоставив свою &amp;quot;эффективную реализацию&amp;quot;.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;br /&gt;
&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;br /&gt;
&amp;nbsp;&lt;/p&gt;&lt;h2&gt;Сборка библиотеки Boost&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;Качаем архив с исходными текстами здесь: &lt;a href="http://www.boost.org/users/download"&gt;http://www.boost.org/users/download/&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;Распаковываем архив в директорию &lt;strong&gt;%BOOST_ROOT%&lt;/strong&gt; (см. статью &lt;a href="http://rakafon.blogspot.com/2009/04/o-acpo-eeoea-install-microsoft-visual.html"&gt;Development Environment Settings&lt;/a&gt;).&lt;br /&gt;
&lt;br /&gt;
Все что вам надо знать на первое время - это:&lt;/li&gt;
&lt;pre&gt;%BOOST_ROOT%\
|---- tools       - инструменты, в частности bjam
|---- boost       - заголовочные файлы boost
|---- libs        - документация
|---- lib   - динамические и статические библиотеки, появятся после сборки
|---- index.html  - начало знакомства с boost
...
&lt;/pre&gt;
&lt;li&gt;Собираем &lt;strong&gt;bjam&lt;/strong&gt; и настраиваем &lt;strong&gt;Boost.Build&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Bjam&lt;/strong&gt; - это мощная утилита, автоматизирующая процесс сборки. Boost.Build - это система сборки на базе bjam, набор скриптов для множества компиляторов, позволяет управлять ими через единый интерфейс. Т.е. вам не надо знать как, например, для gcc настроить precompiled headers…&lt;br /&gt;
&lt;br /&gt;
Запускаем &amp;quot;%BOOST_ROOT%\tools\jam\build_dist.bat&amp;quot;, который собирет bjam.exe&lt;br /&gt;
&lt;br /&gt;
Теперь копируем bjam.exe из &amp;quot;%BOOST_ROOT%\tools\jam\stage\boost-jam-3.1.17-1-ntx86? в &amp;quot;%SystemRoot%\system32&amp;quot; или добавляем директорию &amp;quot;%BOOST_ROOT%\tools\jam\stage\boost-jam-3.1.17-1-ntx86&amp;quot; в системную переменную &lt;strong&gt;PATH&lt;/strong&gt;. Что бы проверить, что все идет по плану - запускаем консоль и выполняем команду:&lt;/li&gt;
&lt;pre&gt;bjam.exe
&lt;/pre&gt;&lt;p&gt;В результате должны получить сообщение:&lt;/p&gt;&lt;pre&gt;Unable to load Boost.Build: could not find &amp;quot;boost-build.jam&amp;quot;
---------------------------------------------------------------
Attempted search from C:\Documents and Settings\Tanya up to the root
and in these directories from BOOST_BUILD_PATH and BOOST_ROOT: D:\c++\libs\boost
_trunk\tools\build\v21, D:\c++\libs\boost_trunk1.
Please consult the documentation at 'http://www.boost.org'.
&lt;/pre&gt;Это сообщене говорит нам о том, что надо настроить &lt;strong&gt;Boost.Build&lt;/strong&gt;.

Для верной работы &lt;strong&gt;Boost.Build&lt;/strong&gt; необходимо существование двух переменных:

&lt;strong&gt;BOOST_ROOT&lt;/strong&gt; - указывает на корневую директорию, куда мы изначально распаковали boost архив (см. статью &lt;a href="http://rakafon.blogspot.com/2009/04/o-acpo-eeoea-install-microsoft-visual.html"&gt;Development Environment Settings&lt;/a&gt;)

&lt;strong&gt;BOOST_BUILD_PATH&lt;/strong&gt; - указывает на %BOOST_ROOT%\tools\build\v2

Важно! Не ставте слэши в конце!

Напомню, что установить системные переменные можно в Панель управления -&amp;gt; Система -&amp;gt; Дополнительно -&amp;gt; Переменные среды -&amp;gt; Системные переменные

Запускаем консоль и выполняем команду:     &lt;pre&gt;bjam.exe
&lt;/pre&gt;&lt;p&gt;Если вы получили следующее сообщение значит вы на правильном пути:&lt;/p&gt;&lt;pre&gt;warning: No toolsets are configured.
warning: Configuring default toolset &amp;quot;msvc&amp;quot;.
warning: If the default is wrong, your build may not work correctly.
warning: Use the &amp;quot;toolset=xxxxx&amp;quot; option to override our guess.
warning: For more configuration options, please consult
warning: http://boost.org/boost-build2/doc/html/bbv2/advanced/configuration.html

error: error: no Jamfile in current directory found, and no target references sp
ecified.
&lt;/pre&gt;
&lt;li&gt;Завершающая стадия - компиляция boost.&lt;br /&gt;
&lt;br /&gt;
Создаем %BOOST_ROOT%\build.bat с содержимым:&lt;/li&gt;
&lt;pre&gt;@echo off
bjam ^
    -j2 ^
    --toolset=msvc-8.0 ^
    release debug ^
    --without-math ^
    --without-graph ^
    --without-python ^
    threading=multi link=static link=shared runtime-link=static runtime-link=shared ^
   stage --stagedir=&amp;quot;./lib&amp;quot;;
   pause
&lt;/pre&gt;
&lt;strong&gt;-j2&lt;/strong&gt; - задействовать два ядра, с целью увеличения скорости компиляции
&lt;strong&gt;--toolset=msvc-8.0&lt;/strong&gt; - инструмент с помощью которого собирать boost (gcc, msvc-8.0, msvc-9.0)
&lt;strong&gt;release debug&lt;/strong&gt; - без коментариев
&lt;strong&gt;--without-math&lt;/strong&gt; - не собирать Boost.Math
&lt;strong&gt;--without-graph&lt;/strong&gt; - не собирать Boost.Graph
&lt;strong&gt;--without-python&lt;/strong&gt; - не собирать Boost.Python
&lt;strong&gt;threading=multi link=static link=shared runtime-link=static runtime-link=shared&lt;/strong&gt; - настраиваем сборку, думаю тут все понятно
&lt;strong&gt;stage&lt;/strong&gt; - директория, в торорую будут помещены статические и динамические библиотеки

Скажу сразу, что процесс сборки достаточно долгий, на моей машине он занимает около 20 минут и требует около 4гб места на диске.     
&lt;li&gt;Для использования boost в своих проектах, настраивайте конфигурацию проектов следующим образом:&lt;br /&gt;
Добавьте путь &amp;quot;$(BOOST_ROOT)&amp;quot; в список &amp;quot;Additional Include Directories&amp;quot; опций компиллятора.&lt;br /&gt;
Добавьте путь &amp;quot;$(BOOST_ROOT)\lib&amp;quot; в список &amp;quot;Additional Library Directories&amp;quot; опций линкера.&lt;br /&gt;
Многие добавляют эти пути в &amp;quot;Tools/Options/Projects and Solutions/VC++ Directories&amp;quot;, однако я так не делаю, и вам не рекомендую, ибо &amp;quot;юзаю/неюзаю&amp;quot; boost есть свойство отдельно проекта, ну накрайняк solution'а, а никак не всей студии, ведь не все проекты, которые, возможно, у вас собираются, зависят от boost, соответсвенно нехрен всяким неандертальским проектам иметь видимость boost'овских заголовочных файлов.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Частично стянуто отсюда: &lt;a href="http://www.gigamega.net/category/boost"&gt;http://www.gigamega.net/category/boost/&lt;/a&gt;&lt;/p&gt;&lt;p&gt;P.S.: Я Boost собираю следующим образом:&lt;br /&gt;
&lt;/p&gt;&lt;pre&gt;&amp;quot;bjam.exe&amp;quot; -j 12 --buid-dir=&amp;quot;build&amp;quot; --build-type=complete --toolset=msvc-8.0 address-model=32 &amp;nbsp;--stagedir=&amp;quot;./lib&amp;quot; stage
&amp;quot;bjam.exe&amp;quot; -j 12 --buid-dir=&amp;quot;build&amp;quot; --build-type=complete --toolset=msvc-9.0 address-model=32 &amp;nbsp;--stagedir=&amp;quot;./lib&amp;quot; stage&lt;/pre&gt;&lt;p&gt;P.P.S.: Улыбнуло мнение, взятое отсюда: &lt;a href="http://www.gigamega.net/category/boost/"&gt;http://www.gigamega.net/category/boost/&lt;/a&gt; :):) : &lt;br /&gt;
Некоторые C++ программисты используют boost, некоторые о нем только слышали, некоторые - нет. Так вот, последние 2 категории - тупиковая ветвь развития (о тех, кому не позволяет железо или компилятор я не говорю), как правило, такие люди даже не доросли до стандартной библиотеки, а их стиль программирования можно назвать “Си с классами”.&lt;/p&gt;&lt;p&gt;P.P.S.: Удачи вам в использовании Boost в ваших проектах!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1252038906587337119-1471411177289337474?l=rakafon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rakafon.blogspot.com/feeds/1471411177289337474/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://rakafon.blogspot.com/2009/04/boost-boost-c.html#comment-form' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/1471411177289337474'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1252038906587337119/posts/default/1471411177289337474'/><link rel='alternate' type='text/html' href='http://rakafon.blogspot.com/2009/04/boost-boost-c.html' title='Библиотека Boost'/><author><name>Rakafon</name><uri>http://www.blogger.com/profile/03386514126069055282</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-wnns05XIxW4/Ti7XTMmujOI/AAAAAAAAABg/rZpn54sM7BI/s1600/20168127'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1252038906587337119.post-3316096199262493727</id><published>2009-04-01T13:00:00.003+03:00</published><updated>2010-10-15T14:39:57.769+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IDE'/><category scheme='http://www.blogger.com/atom/ns#' term='VCS'/><category scheme='http://www.blogger.com/atom/ns#' term='cpp'/><title type='text'>Мoи нacтpoйки для дeвeлoпмeнтa</title><content type='html'>&lt;ul&gt;&lt;li&gt;Install Microsoft Visual Studio 2005. (or 2008)&lt;/li&gt;
&lt;li&gt;Install 
