Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь 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; просмотров: 241; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.146.107.144 (0.012 с.) |