![]() |
![]() ![]() ![]() ![]() ![]() |
![]() |
Annex: ImplementationBoost , Chapter 1. Boost.LocalFunction 1.0.0 , Chapter 1. Boost.LocalFunction 1.0.0
|
![]() | Note |
---|---|
Перечисленный здесь код может быть использован любопытными читателями и хранителями библиотеки в качестве ссылки при попытке понять исходный код библиотеки. Нет абсолютно никакой гарантии, что реализация библиотеки использует точный код, указанный здесь. |
Эта библиотека использует локальный класс для реализации локального функционального объекта. Однако вC++03локальные классы (и, следовательно, локальные объекты функций, которые они реализуют) не могут быть переданы в качестве параметров шаблона (например, алгоритму<std::for_each
>), это вместо этого возможно вC++11, MSVC и некоторых других компиляторах (см.[N2657]).иBoost.Config's<BOOST_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS
>. Чтобы обойти это ограничение, эта библиотека исследовала следующие два «трюка» (оба трюка могут быть расширены для поддержки параметров по умолчанию функции):
void*
>(местные классы всегда могут использоваться для отливки по типу через<static_cast
>или аналогично).operator()
>называется динамической привязкой.Например (см. также<impl_tparam_tricks.cpp
>):
#include <boost/detail/lightweight_test.hpp> #include <vector> #include <algorithm> // Casting functor trick. struct casting_func { explicit casting_func(void* obj, void (*call)(void*, const int&)) : obj_(obj), call_(call) {} // Unfortunately, function pointer call is not inlined. inline void operator()(const int& num) { call_(obj_, num); } private: void* obj_; void (*call_)(void*, const int&); }; // Virtual functor trick. struct virtual_func { struct interface { // Unfortunately, virtual function call is not inlined. inline virtual void operator()(const int&) {} }; explicit virtual_func(interface& func): func_(&func) {} inline void operator()(const int& num) { (*func_)(num); } private: interface* func_; }; int main(void) { int sum = 0, factor = 10; // Local class for local function. struct local_add : virtual_func::interface { explicit local_add(int& _sum, const int& _factor) : sum_(_sum), factor_(_factor) {} inline void operator()(const int& num) { body(sum_, factor_, num); } inline static void call(void* obj, const int& num) { local_add* self = static_cast<local_add*>(obj); self->body(self->sum_, self->factor_, num); } private: int& sum_; const int& factor_; inline void body(int& sum, const int& factor, const int& num) { sum += factor * num; } } add_local(sum, factor); casting_func add_casting(&add_local, &local_add::call); virtual_func add_virtual(add_local); std::vector<int> v(10); std::fill(v.begin(), v.end(), 1); // std::for_each(v.begin(), v.end(), add_local); // Error but OK on C++11. std::for_each(v.begin(), v.end(), add_casting); // OK. std::for_each(v.begin(), v.end(), add_virtual); // OK. BOOST_TEST(sum == 200); return boost::report_errors(); }
Трюк литья функтора измерял несколько лучшие показатели времени выполнения, чем трюк виртуального функтора, поэтому текущая реализация этой библиотеки использует трюк литья функтора (вероятно, потому что в дополнение к вызову косвенной функции трюк виртуального функтора также требует доступа к таблицевиртуальной функции). Тем не менее, ни один из двух приемов не позволял оптимизировать компилятор, который встраивает локальные вызовы функций (потому что они полагаются на один непрямой вызов функций через указатель функций или виртуальную функцию соответственно). Поэтому на компиляторах, которые принимают локальные классы в качестве параметров шаблона (MSVC,C++11и т. д., см.[N2657]иBoost.Config's<BOOST_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS
>), эта библиотека автоматически генерирует код, который передает локальный тип класса непосредственно в качестве параметра шаблона без использования ни одного из этих двух трюков, чтобы в полной мере воспользоваться оптимизацией компилятора, которая встраивает вызовы локальной функции.
Эти библиотечные макросы могут анализировать список заданных параметров и обнаруживать, соответствует ли какое-либо из связанных имен переменных токену<this_
>(создавать специальный код для связывания объекта в объеме), или если переменная связана<const
>(создавать специальный код для связывания константой) и т.д. Токены параметров проверяются с помощью метапрограммирования препроцессора и, в частности, с использованием макросов, определенных файлами в каталоге<boost/local_function/detail/preprocessor/keyword/
>.
Например, следующий код определяет макрос, который позволяет препроцессору определить, заканчивается ли набор пространственно-отделенных токенов<this_
>или нет (см. также<impl_pp_keyword.cpp
>):
#include <boost/local_function/detail/preprocessor/keyword/thisunderscore.hpp> #include <boost/local_function/detail/preprocessor/keyword/const.hpp> #include <boost/local_function/detail/preprocessor/keyword/bind.hpp> #include <boost/detail/lightweight_test.hpp> // Expand to 1 if space-separated tokens end with `this_`, 0 otherwise. #define IS_THIS_BACK(tokens) \ BOOST_LOCAL_FUNCTION_DETAIL_PP_KEYWORD_IS_THISUNDERSCORE_BACK( \ BOOST_LOCAL_FUNCTION_DETAIL_PP_KEYWORD_BIND_REMOVE_FRONT( \ BOOST_LOCAL_FUNCTION_DETAIL_PP_KEYWORD_CONST_REMOVE_FRONT( \ tokens \ ))) int main(void) { BOOST_TEST(IS_THIS_BACK(const bind this_) == 1); BOOST_TEST(IS_THIS_BACK(const bind& x) == 0); return boost::report_errors(); }
Этот метод лежит в основе еще более сложных макросов анализа препроцессоров, таких как синтаксисContract++.
Статья Annex: Implementation раздела Chapter 1. Boost.LocalFunction 1.0.0 Chapter 1. Boost.LocalFunction 1.0.0 может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.
:: Главная :: Chapter 1. Boost.LocalFunction 1.0.0 ::
реклама |