Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву
Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Использование с указателями на функции членыСодержание книги
Поиск на нашем сайте Помимо указателей на глобальные функции и функторов, в качестве первого параметра можно указывать указатель на функцию-член какого-то класса. Предположим один из простейших вариантов использования: class GraphicsObject { public: void Draw(Canvas* canvas, DrawModes mode); }; // Объявляем коллекцию объектов этого класса: std::list<GraphicsObject*> GraphObjects; // А теперь нам нужно отрисовать все объекты коллекции на заданном канвасе std::for_each(GraphObjects.begin(), GraphObjects.end(); ……..); при использовании чистого STL нам бы пришлось писать свой собственный функтор, вызывающий у переданного объекта метод Draw с заданными параметрами. Но можно воспользоваться boost::bind: std::for_each(GraphObjects.begin(), GraphObjects.end(), boost::bind(&GraphObject::Draw, _1, canvas, mode)); в результате чего мы получаем требуемый результат. У всех объектов коллекции вызывается метод Draw, которому передаются параметры canvas и mode. При использовании указателя на функцию-член класса необходимо помнить о том, что первым параметром ей должен передаваться указатель на объект, для которого эта функция должна вызываться. В приведенном примере мы указываем, что метод должен вызываться у переданного в bind единственного параметра. Но никто не мешает нам в качестве первого передаваемого параметра указать this, или любой другой указатель. Но, как говориться в современных набивших оскомину рекламах, это еще не все. Использование с указателем на член данных Помимо указателей на члены-функции можно использовать указатели на члены данных. Синтаксис подобный и правила использования при этом почти такие же. Возьмем задачу. Есть структура и вектор ее экземпляров: struct Point {
int x; int y; };
std::vector<Point> PointsArray; Теперь надо удалить из этого массива все элементы, у которых координата x равна нулю. Сделать это просто: std::remove_if(PointsArray.begin(), PointsArray.end(), boost::bind(std::equal_to<int>(), boost::bind(&Point::x, _1), 0)); Т. е. для каждого элемента массива вызывается вложенный связыватель, который возвращает значение соответствующего элемента структуры, после чего производится его сравнение с нулем. Тут мы видим еще одну возможность связывателей: Каскадное использование связывателей Связыватели могут вкладываться друг в друга. Один из вариантов такого вкладывания проиллюстрирован предыдущем примером. Единственное, что в этом случае надо «держать в голове» - это то, что плейсхолдеры, вне зависимости от того, в каком bind'ере (по уровню вложенности) они находятся, «адресуют» параметры самого внешго binder'а. Усложним предыдущий пример. Нужно выбросить все точки, имеющие нулевые координаты: std::remove_if(PointsArray.begin(), PointsArray.end(), boost::bind(
std::logical_and(), boost::bind(std::equal_to<int>(), boost::bind(&Point::x, _1), 0), boost::bind(std::equal_to<int>(), boost::bind(&Point::y, _1), 0)
) )); Это хотя и работает так, как хочется, но выглядит слишком наворочено. По этому начиная с версии 1.33 в boost::bind появилась новая возможность - Перегруженные операторы Для упрощения приведенных выше многоэтажных конструкций для boost::bind (начиная с версии 1.33 boost'а) перегружены следующие операторы:!, ==, !=, <,?, > и >=. Таким образом, приведенное выше выражение упрощается до: std::remove_if(PointsArray.begin(), PointsArray.end(), boost::bind(
boost::bind(&Point::x, _1) == 0 && boost::bind(&Point::y, _1) == 0)
)); Использование ссылок Одна из неприятностей заключается в том, что если связываемая функция принимает какой-то из своих аргументов по ссылке, то с использованием boost::bind его (напрямую) передать нельзя. Т. е. например, в следующем случае: void foo(int& a, int& b);
int a = 1, b = 2; boost::bind(foo, a, b); аргументы a и b по ссылке переданы не будут. Для того, чтобы действительно передать ссылки, необходимо делать такой вызов: boost::bind(foo, boost::ref(a), boost::ref(b)); В этом случае foo, вызываемый из связывателя, будет действительно работать со ссылками на соответствующие переменные. Полную документацию и примеры использования можно найти в оригинальной документации: http://www.boost.org/libs/bind/bind.html Пример использования. #include <vector> #include <boost/bind.hpp> #include <boost/function.hpp> class Test { public: void f_1() { std::cout << "void f()" << std::endl; } void f_2(int i) { std::cout << "void f_2(): " << i << std::endl; } void f_3(const int &i) { std::cout << "void f_2(): " << i << std::endl; } void two_params(int a, int b) { std::cout << "void two_params(int a, int b): " << a << ", " << b << std::endl; } };
class Test2 { public: void do_stuff(const std::vector<int>& v) { std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " ")); } };
void test(const std::string &a) { std::cout << "void test(const std::string &a). a = " << a << std::endl; }
void prn(boost::function<void(int)> fn, int a) { fn(a); }
int _tmain(int argc, _TCHAR* argv[]) { ////////////////////// bind ////////////////////// std::cout << "boost::bind test" << std::endl; Test a; boost::bind(&Test::f_1, &a)();
boost::bind(&Test::f_2, &a, 1)(); int test_int(2); boost::bind(&Test::f_2, &a, _1)(test_int);
boost::bind(&Test::f_3, &a, 3)(); int test_int_2(4); boost::bind(&Test::f_3, &a, _1)(test_int_2);
int one(100), two(200); boost::bind(&Test::two_params, &a, _1, _2)(one, two); boost::bind(&Test::two_params, &a, _2, _1)(one, two);
std::string test_str("Hi there."); boost::bind(&test, test_str)(); boost::bind(&test, _1)(test_str); std::cout << std::endl;
////////////////////// function ////////////////////// std::cout << "boost::function test" << std::endl;
boost::function<void(void)> func; func = boost::bind(&Test::f_1, &a); func(); func = boost::bind(&Test::f_2, &a, 201); func(); func = boost::bind(&Test::f_3, &a, 202); func(); func = boost::bind(&Test::two_params, &a, 203, 204); func();
boost::function<void(int)> func_2; func_2 = boost::bind(&Test::f_2, &a, _1); prn(func_2, 301); func_2 = boost::bind(&Test::f_3, &a, _1); prn(func_2, 302);
int i_303(303), i_304(304), i_305(305), i_306(306); func_2 = boost::bind(&Test::two_params, &a, i_303, _1); prn(func_2, 1); func_2 = boost::bind(&Test::two_params, &a, _1, i_304); prn(func_2, 1);
Test2 t; std::vector<int> vec; vec.resize(20); std::generate_n(vec.begin(), 20, rand); std::copy(vec.begin(), vec.end(), std::ostream_iterator<int>(std::cout, " ")); //simple_bind(&Test::do_stuff, t, _1)(vec); //boost::bind(&Test2::do_stuff, t, _1)(vec);
return 0; }
23.5. BOOST::ASIO (::IO_SERVICE) (Самостоятельное изучение) Boost::asio основы boost::asio на самом деле, хоть и называется библиотекой асинхронной, но может выполнять и синхронные, и асинхронные операции. Вся библиотека при этом завязана на объекты класса boost::asio::io_service – именно asio::io_service предоставляет программе связь с нативными объектами ввода/вывода. Соответственно, что бы ваша программа могла работать с boost::asio, нужно создать хотя бы один объект этого класса и уже после этого “аттачить” все другие объекты к нему, например вот так:
Подключить только что созданный сокет к серверу тоже не представляет из себя проблемы:
После того как мы подключили объекты ввода-вывода (в данном случае socket) к asio::io_service – этот сервис будет осуществлять взаимодействие с операционной системой и получать/отправлять данные. Boost::asio асинхронный Тот вариант, что мы рассмотрели выше – это синхронное взаимодействие, т.е., в данном случае это значит, что пока происходит подключение – наша программа “зависнет” до того момента, пока подключение не выполнится, либо не произойдёт ошибка. Если же мы хотим что бы работа boost::asio была асинхронной, надо идти немного другим путём, который тоже предусмотрен в библиотеке. Для работы с асинхронными операциями мы должны передать в функцию так называемый completion handler, или, говоря по русски, функцию, которая будет вызвана, когда операция завершится (т.е. либо подключится, либо возникнет ошибка):
Все асинхронные функции в boost::asio работают именно по такому принципу. С одной стороны, это довольно удобно для программирования – логика работы каждой из функций отделена от других, с другой стороны это может может показаться Вам немного непривычным. Но, я уверен, Вы освоитесь Использование boost::asio Приведу короткий и простой пример использования boost::asio, это код примера из самого boost, лишь перевёл комментарии: #include <iostream> #include <istream> #include <ostream> #include <string> #include <boost/asio.hpp>
using boost::asio::ip::tcp;
int main(int argc, char* argv[]) { try { if (argc!= 3) // если аргументы не заданы или заданы не все { std::cout << "Usage: sync_client <server> <path>\n"; std::cout << "Example:\n"; std::cout << " sync_client www.boost.org /LICENSE_1_0.txt\n"; return 1; }
boost::asio::io_service io_service; // основной класс asio
// Получаем список конечных точек для указанного сервера tcp::resolver resolver(io_service); tcp::resolver::query query(argv[1], "http"); tcp::resolver::iterator endpoint_iterator = resolver.resolve(query); tcp::resolver::iterator end;
// Перебираем эти конечные точки и пробуем подключиться tcp::socket socket(io_service); boost::system::error_code error = boost::asio::error::host_not_found; while (error && endpoint_iterator!= end) { socket.close(); socket.connect(*endpoint_iterator++, error); } if (error) // подключиться не удалось throw boost::system::system_error(error);
// Формируем запрос к веб-серверу. Указываем "Connection: close" что бы // сервер закрыл соединение как только отправит нам данные. Это // позволит нам узнать что отправка завершенна как только возникнет EOF boost::asio::streambuf request; std::ostream request_stream(&request); request_stream << "GET " << argv[2] << " HTTP/1.0\r\n"; request_stream << "Host: " << argv[1] << "\r\n"; request_stream << "Accept: */*\r\n"; request_stream << "Connection: close\r\n\r\n";
// Отправляем сформированный запрос веб-серверу. boost::asio::write(socket, request);
// Читаем ответ сервер. streambuf response примет все данные // он сам будет увеличиваться по мере поступления данных от сервера. boost::asio::streambuf response; boost::asio::read_until(socket, response, "\r\n");
// Проверяем что бы не было ошибок. std::istream response_stream(&response); std::string http_version; response_stream >> http_version; unsigned int status_code; response_stream >> status_code; std::string status_message; std::getline(response_stream, status_message); if (!response_stream || http_version.substr(0, 5)!= "HTTP/") // ошибка { std::cout << "Invalid response\n"; return 1; } if (status_code!= 200) // если код ответа не 200, то это тоже ошибка { std::cout << "Response returned with status code " << status_code << "\n"; return 1; }
// Читаем ответ. Он закончится пустой строкой. boost::asio::read_until(socket, response, "\r\n\r\n");
// Парсим заголовки std::string header; while (std::getline(response_stream, header) && header!= "\r") std::cout << header << "\n"; std::cout << "\n";
// Выводим в лог if (response.size() > 0) std::cout << &response;
// Теперь читаем до конца while (boost::asio::read(socket, response, boost::asio::transfer_at_least(1), error)) std::cout << &response;
if (error!= boost::asio::error::eof) // ошибка throw boost::system::system_error(error); } catch (std::exception& e) // возникло исключение { std::cout << "Exception: " << e.what() << "\n"; }
return 0; }
Вот эти 100 строк кода работают как HTTP-клиент и позволяют нам читать страницы с веб-серверов. Мне кажется, что код не сложный, особенно, когда он с комментариями.
|
|||||
|
Последнее изменение этой страницы: 2016-12-11; просмотров: 334; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 216.73.217.21 (0.008 с.) |