1. Введение

1.1. Характеристика библиотеки

1.2. Тематики библиотек

  1. RAII и управление памятью
  2. Обработка строк
  3. Контейнеры
  4. Структуры данных
  5. Алгоритмы
  6. Межпроцессорное взаимодействие
  7. Потоки и файлы
  8. Время
  9. Функциональное программирование
  1. Параллельное программирование
  2. Обобщённое программирование
  3. Языковые исключения
  4. Обработка ошибок
  5. Работа с числами
  6. Библиотеки для работы с приложением
  7. Дизайн паттерны
  8. Другие библиотеки

2. RAII и управление памятью

2.1. Умные указатели

auto sp = std::make_shared<T>(123, "abc");
std::weak_ptr wp{sp};
std::shared_ptr<T> sh = wp.lock();
if (sh)
    std::cout << sh->str;

Адаптации:

2.2. Умный контейнер для указателей

boost::ptr_set<int> s;
s.insert(new int{2});
s.insert(std::make_unique(1));
std::cout << *s.begin() << '\n';

Аналогично без использования умного контейнера:

std::set<std::unique_ptr<int>, boost::indirect_fun<std::less<int>>> v;
v.insert(std::make_unique_ptr(2));
v.insert(std::make_unique_ptr(1));
std::cout << **v.begin() << '\n';

2.3. Автоматическое освобождение ресурсов

BOOST_SCOPE_EXIT(&commit, this_) {
    if(!commit)
        this_->persons_.pop_back();
} BOOST_SCOPE_EXIT_END

BOOST_SCOPE_EXIT_ALL(&, checkpoint, this) {
    if(checkpoint == p.evolution)
        this->persons_.pop_back();
};

2.4. Пул для работы с памятью

boost::object_pool<int> pool;

int *i = pool.malloc();
*i = 1;

pool.destroy(i);

boost::simple_segregated_storage<std::size_t> storage;
std::vector<char> v(42);
storage.add_block(&v.front(), v.size(), 11);

int *n = static_cast<int*>(storage.malloc());
*n = 45;

storage.free(n);

std::vector<int, boost::pool_allocator<int>> v{{7, 8, 99}};
...
boost::singleton_pool<boost::pool_allocator_tag, sizeof(int)>::purge_memory();

3. Обработка строк

3.1. Строковые алгоритмы

1 Символ * — это first, nth, last, all, head, tail

3.2. Лексические преобразования

std::string s = boost::lexical_cast<std::string>(123);
double d = boost::lexical_cast<double>(s);
std::cout << s << " == " << d << std::endl;

3.3. Форматированный вывод

#include <iostream>

#include <boost/format.hpp>

int main()
{
    std::cout << boost::format("%|1$#x| %2% %1%\n") % 123 % 456 << std::endl;
}
Output
0x7b 456 123

3.4. Регулярные выражения

#include <iostream>
#include <regex>

int main()
{
    std::string s = "Boost Libraries";
    std::regex expr{R"((\w+)\s*(\w+))"};
    if (std::smatch what; std::regex_search(s, what, expr))
    {
        std::cout << what[0] << '\n';
        std::cout << what[1] << "_" << what[2] << '\n';
    }
}
Output
Boost Libraries
Boost_Libraries

3.5. Xpressive

#include <iostream>
#include <iterator>
#include <string>

#include <boost/xpressive/xpressive.hpp>
#include <boost/xpressive/regex_actions.hpp>

int main()
{
    namespace xpr = boost::xpressive;

    std::string s{"Boost Libraries"};
    auto r = xpr::sregex::compile(R"(\w+\s*\w+)");
    xpr::sregex r2 = +xpr::_w >> xpr::_s >> +xpr::_w;
    std::cout << xpr::regex_match(s, r) << " == " << xpr::regex_match(s, r2) << std::endl;

    std::ostream_iterator<std::string> it{std::cout, "\n"};
    xpr::sregex r3 = (+xpr::_w)[*xpr::ref(it) = xpr::_] >> xpr::_s >> +xpr::_w;
    std::cout << std::boolalpha << xpr::regex_match(s, r3) << std::endl;
}
Output
1 == 1
Boost
true

3.6. Токенайзер

#include <iostream>
#include <string>

#include <boost/tokenizer.hpp>

int main()
{
    std::string_view s{"Boost C++ Libraries"};
    boost::char_separator<char> sep{" ", "+", boost::keep_empty_tokens};
    boost::tokenizer tok{s, sep};
    for (const auto& t : tok)
        std::cout << t << '\n';
}
Output
Boost
C
+

+

Libraries

3.7. Spirit

4. Контейнеры

4.1. Мульти-индекс

Интерфейс Совместимый тип

sequenced

std::list

hashed_unique

std::unordered_set

hashed_non_unique

std::unordered_multiset

ordered_non_unique

std::multiset

ordered_unique

std::set

random_access

std::vector

» 4.1. (продолжение)

#include <iostream>

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/multi_index/member.hpp>

int main()
{
    struct animal
    {
        std::string name;
        int legs;
    };

    boost::multi_index::multi_index_container<
        animal,
        boost::multi_index::indexed_by<
            boost::multi_index::sequenced<>,
            boost::multi_index::ordered_non_unique<
                boost::multi_index::member<
                    animal, int, &animal::legs
                >
            >,
            boost::multi_index::random_access<>
        >
    > animals;

    animals.emplace_back("cat", 4);
    animals.emplace_back("shark", 0);
    animals.emplace_back("spider", 8);

    auto& legs_index = animals.get<1>();
    auto it = legs_index.find(4);
    legs_index.modify(it, [](animal &a){ a.name = "dog"; });

    for (const auto& x : animals)
        std::cout << x.name << " " << x.legs << "\n";
}
Output
dog 4
shark 0
spider 8

4.2. Bimap

#include <iostream>
#include <string>

#include <boost/bimap.hpp>
#include <boost/bimap/support/lambda.hpp>

int main()
{
    boost::bimap<std::string, boost::bimaps::unconstrained_set_of<int>> animals;

    animals.insert({"cat", 4});
    animals.insert({"shark", 0});
    animals.insert({"spider", 8});

    auto it = animals.left.find("cat");
    animals.left.modify_key(it, boost::bimaps::_key = "dog");

    for (const auto& [key, val] : animals)
        std::cout << key << ":" << val << "\n";
}
Output
dog:4
shark:0
spider:8

4.3. Array

4.4. Неупорядоченные (ассоциативные) массивы

4.5. Циклический буфер

#include <iostream>

#include <boost/circular_buffer.hpp>

int main()
{
    boost::circular_buffer<int> cb{3};

    cb.push_back(0);
    cb.push_back(1);
    cb.push_back(2);
    cb.push_back(3);

    std::cout << std::boolalpha << cb.is_linearized() << '\n';

    auto ar1 = cb.array_one();
    auto ar2 = cb.array_two();
    std::cout << ar1.second << ";" << ar2.second << std::endl;
}
Output
false
2;1

4.6. Куча

#include <algorithm>
#include <iostream>
#include <iterator>

#include <boost/heap/binomial_heap.hpp>

int main()
{
    boost::heap::binomial_heap<int> bh;
    bh.push(2);
    bh.push(3);
    bh.push(1);

    boost::heap::binomial_heap<int> bh2;
    bh2.push(4);
    bh.merge(bh2);

    std::copy(bh.ordered_begin(), bh.ordered_end(), std::ostream_iterator<int>(std::cout, "\n"));
}
Output
4
3
2
1

4.7. Intrusive

#include <iostream>

#include <boost/intrusive/list.hpp>

int main()
{
    struct animal : public boost::intrusive::list_base_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink>>
    {
        std::string name;
        int legs;

        animal(std::string name, int legs) : name(std::move(name)), legs(legs)
        {}
    };

    animal a1{"cat", 4};
    animal a2{"ostrich", 2};
    animal *a3 = new animal{"spider", 8};

    boost::intrusive::list<animal, boost::intrusive::constant_time_size<false>> animals;

    animals.push_back(a1);
    animals.push_back(a2);
    animals.push_back(*a3);

    delete a3;

    for (const animal &a : animals)
        std::cout << a.name << '\n';
}
Output
cat
ostrich

4.8. Массивы произвольной размерности

#include <algorithm>
#include <array>
#include <iostream>
#include <experimental/iterator>

#include <boost/multi_array.hpp>

int main()
{
    boost::multi_array<double, 3> a{boost::extents[3][6][8]};
    a[0][0][7] = 3.14;
    a(std::array{1, 1, 7}) = 2.718;

    using range = boost::multi_array_types::index_range;
    using index = range::index;
    auto view = a[boost::indices[range()][range() < index(5)][index(4) <= range().stride(2) <= index(7)]];

    for (auto v1 : view)
        for (auto v2 : v1)
            for (auto& x : v2)
                x = 77;

    for (const auto& v1 : a)
    {
        for (const auto& v2 : v1)
        {
            std::copy(v2.begin(), v2.end(), std::experimental::make_ostream_joiner(std::cout, ", "));
            std::cout << "\n";
        }

        std::cout << "\n";
    }
}
Output
0, 0, 0, 0, 77, 0, 77, 3.14
0, 0, 0, 0, 77, 0, 77, 0
0, 0, 0, 0, 77, 0, 77, 0
0, 0, 0, 0, 77, 0, 77, 0
0, 0, 0, 0, 77, 0, 77, 0
0, 0, 0, 0, 0, 0, 0, 0

0, 0, 0, 0, 77, 0, 77, 0
0, 0, 0, 0, 77, 0, 77, 2.718
0, 0, 0, 0, 77, 0, 77, 0
0, 0, 0, 0, 77, 0, 77, 0
0, 0, 0, 0, 77, 0, 77, 0
0, 0, 0, 0, 0, 0, 0, 0

0, 0, 0, 0, 77, 0, 77, 0
0, 0, 0, 0, 77, 0, 77, 0
0, 0, 0, 0, 77, 0, 77, 0
0, 0, 0, 0, 77, 0, 77, 0
0, 0, 0, 0, 77, 0, 77, 0
0, 0, 0, 0, 0, 0, 0, 0

4.9. Остальные контейнеры

5. Структуры данных

5.1. Вошедшие в STL

5.2. Дерево свойств

» 5.2. (продолжение)

#include <iostream>
#include <string>

#include <boost/property_tree/ptree.hpp>

int main()
{
    namespace bpt = boost::property_tree;

    bpt::ptree pt;
    pt.put("drive.win.system", "20 files");

    auto c = pt.get_optional<std::string>("drive");
    std::cout << std::boolalpha << c.is_initialized() << '\n';

    pt.put_child("drv.files", bpt::ptree{"50 files"});
    pt.add_child("drv.files", bpt::ptree{"60 files"});

    bpt::ptree d = pt.get_child("drv");
    for (const auto& [key, val] : d)
        std::cout << val.get_value<std::string>() << '\n';

    boost::optional<bpt::ptree&> e = pt.get_child_optional("ala");
    std::cout << e.is_initialized() << std::endl;
}
Output
true
50 files
60 files
false

5.3. Динамический bitset

#include <iostream>
#include <vector>
#include <string>

#include <boost/dynamic_bitset.hpp>

int main()
{
    boost::dynamic_bitset<uint32_t> db(std::string("11010110101"));

    std::vector<uint32_t> v{{8, 779, 65564, 5321, 556}};
    db.append(v.begin(), v.end());
    db.push_back(true);
    db.append(4485);

    std::cout.setf(std::ios::boolalpha);
    std::cout << db.size() << '\n';
    std::cout << db.count() << '\n';
    std::cout << db.any() << '\n';
    std::cout << db.none() << '\n';

    std::cout << db[0].flip() << '\n';
    std::cout << ~db[3] << '\n';

    std::vector<uint32_t> out;
    boost::to_block_range(db, std::back_inserter(out));
    for (auto x : out)
        std::cout << x << "\n";
}
Output
204
33
true
false
false
true
18100
1595392
134275072
10897408
1138688
18372608
0

5.4. Трёхзначный булевый тип

#include <iostream>

#include <boost/logic/tribool.hpp>
#include <boost/logic/tribool_io.hpp>

int main()
{
    using namespace boost::logic;

    std::cout.setf(std::ios::boolalpha);

    boost::logic::tribool b1 = true;
    std::cout << (b1 || indeterminate) << '\n';
    std::cout << (b1 && indeterminate) << '\n';

    boost::logic::tribool b2 = false;
    std::cout << (b2 || indeterminate) << '\n';
    std::cout << (b2 && indeterminate) << '\n';

    boost::logic::tribool b3 = boost::logic::indeterminate;
    std::cout << (b3 || b3) << '\n';
    std::cout << (b3 && b3) << '\n';
}
Output
true
indeterminate
indeterminate
false
indeterminate
indeterminate

5.5. Сжатые пары

#include <iostream>
#include <utility>

#include <boost/compressed_pair.hpp>

int main()
{
    struct empty {};

    std::pair<int, empty> p;
    boost::compressed_pair<int, empty> cp;
    std::cout << sizeof(p) << " vs. " << sizeof(cp) << std::endl;
}
Output
8 vs. 4

6. Алгоритмы

6.1. Обобщённые алгоритмы

#include <iostream>
#include <iterator>
#include <string>
#include <vector>

#include <boost/algorithm/hex.hpp>
#include <boost/algorithm/gather.hpp>

int main()
{
    namespace ba = boost::algorithm;

    std::cout << ba::unhex(std::string("432b2b")) << '\n';
    ba::hex(std::vector<char>{'C', '+', '+'}, std::ostream_iterator<char>(std::cout, ""));
    std::cout << "\n";

    std::vector v{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}};
    auto p = ba::gather(v.begin(), v.end(), v.begin() + 4, [](auto x) { return x % 2 == 0; });
    for (auto it = p.first; it != p.second; ++it)
        std::cout << *it << " ";

    std::cout << "\n";
}
Output
C++
432B2B
0 2 4 6 8

6.2. Диапазоны

» 6.2. (продолжение)

#include <iostream>
#include <string>
#include <experimental/iterator>

#include <boost/range/irange.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <boost/range/istream_range.hpp>

int main()
{
    auto ir = boost::irange(0, 3);
    boost::copy(ir, std::experimental::make_ostream_joiner(std::cout, ", "));
    std::cout << "\n";

    auto sr = boost::istream_range<int>(std::cin);
    boost::copy(sr, std::ostream_iterator<int>{std::cout, "\n"});
}
Output
$ ./example5-2 <<< "45 89 53"
0, 1, 2
45
89
53

6.3. Граф (BGL)

https://www.boost.org/doc/libs/1_68_0/libs/graph/doc/figs/adj-matrix-graph2.gif
Рисунок 1. Пример направленного графа
https://www.boost.org/doc/libs/1_68_0/libs/graph/doc/figs/adj-list2.gif
Рисунок 1. Пример хранения графа в adjacency_list
enum vertex { A, B, C, D, E, F };
std::vector<std::pair<vertex, vertex>> edges{{
    {B, C}, {B, F},
    {C, A}, {C, C},
    {D, E},
    {E, D},
    {F, A}
}};

std::array weights{{2, 1, 1, 1, 3, 4, 2}};
boost::adjacency_list<boost::vecS, boost::vecS, boos::undirectedS> g{6, edges.begin(), edges.end(), weights.begin()};

auto [first, last] = boost::edges(g);
std::copy(first, last, std::ostream_iterator<typename decltype(g)::edge_descriptor>(std::cout, "\n"));

6.4. Алгоритмы на графах

boost::array<int, 6> directions;
boost::dijkstra_shortest_paths(g, B, boost::predecessor_map(directions.begin()));

int p = A;
while (p != B)
{
    std::cout << p << '\n';
    p = directions[p];
}
std::cout << p << std::endl;

7. Межпроцессорное взаимодействие

7.1. Asio

#include <iostream>

#include <boost/asio.hpp>

int main()
{
    using namespace std::literals;

    boost::asio::io_service ioservice;

    boost::asio::steady_timer timer1{ioservice, 3s};
    timer1.async_wait([](auto) { std::cout << "3 sec\n"; });

    boost::asio::steady_timer timer2{ioservice, 4s};
    timer2.async_wait([](auto) { std::cout << "4 sec\n"; });

    ioservice.run();
}
Output
3 sec
4 sec

7.2. Работа с сетью в boost::asio

» 7.2. (продолжение)

» 7.2. (продолжение)

7.3. Разделяемая память

#include <iostream>

#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>

int main()
{
    namespace bi = boost::interprocess;

    bi::shared_memory_object shdmem{bi::open_or_create, "Boost", bi::read_write};
    shdmem.truncate(1024);
    bi::mapped_region region{shdmem, bi::read_write};
    int *i1 = static_cast<int*>(region.get_address());
    *i1 = 99;

    bi::mapped_region region2{shdmem, bi::read_only};
    int *i2 = static_cast<int*>(region2.get_address());
    std::cout << *i2 << std::endl;
}
Output
99

7.4. Управляемая разделяемая память

shared_memory_object::remove("Boost");
managed_shared_memory managed_shm{open_or_create, "Boost", 1024};

int *i = managed_shm.construct<int>("Integer")[10](99);
std::cout << *i << "\n";

std::pair<int*, std::size_t> p = managed_shm.find<int>("Integer");
if (p.first)
    std::cout << *p.first << ":" << p.second << "\n";

using char_allocator = boost::allocator<char, managed_shared_memory::segment_manager>;
using string = boost::basic_string<char, std::char_traits<char>, char_allocator> string;
string* s = managed_shm.find_or_construct<string>("String")("Hello!", managed_shm.get_segment_manager());
s->insert(5, ", world");
std::cout << *s << std::endl;

managed_shm.destroy<int>("Integer");

7.5. Разделяемые объекты синхронизации

managed_shared_memory managed_shm{open_or_create, "shm", 1024};
int *i = managed_shm.find_or_construct<int>("Integer")(0);
interprocess_mutex *mtx = managed_shm.find_or_construct<interprocess_mutex>("mtx")();
named_condition named_cnd{open_or_create, "cnd"};
std::lock_guard lock{*mtx};
while (*i < 10)
{
    if (*i % 2 == 0)
    {
        ++(*i);
        cnd->notify_all();
        cnd->wait(lock);
    }
    else
    {
      std::cout << *i << std::endl;
      ++(*i);
      cnd->notify_all();
      cnd->wait(lock);
    }
}
cnd->notify_all();
shared_memory_object::remove("shm");

8. Потоки ввода/вывода и файлы

8.1. Потоки ввода/вывода

namespace bio = boost::iostreams;

std::vector<char> v;
bio::back_insert_device<std::vector<char>> sink{v};
bio::stream os{sink};
os << "Boost" << std::endl;

bio::file_source f{"text.txt"};
if (f.is_open())
{
    bio::stream is{f};
    std::cout << is.rdbuf() << std::endl;
}

8.2. Фильтры потока ввода/вывода

namespace bio = boost::iostreams;

std::vector<char> v;
bio::back_insert_device<std::vector<char>> snk{v};
bio::filtering_ostream os;
os.push(bio::zlib_compressor{});
os.push(snk);
os << "Boost" << std::flush;
os.pop();

bio::array_source src{v.data(), v.size()};
bio::filtering_istream is;
is.push(bio::zlib_decompressor{});
is.push(bio::counter{});
is.push(src);
std::string s;
is >> s;

auto *c = os.component<counter>(0);
std::cout << s << "\n"
          << "Stats: characters = " << c->characters() << " lines = " << c->lines() << std::endl;

8.3. Работа с файловой системой

9. Работа со временем

9.1. Календарь

#include <iostream>

#include <boost/date_time/gregorian/gregorian.hpp>

int main()
{
    namespace bg = boost::gregorian;

    bg::date d{2018, 11, 19};
    bg::months ms{1};
    bg::date d2 = d + ms;
    bg::date d3 = d2 - ms;
    std::cout << d2 << " vs. " << d3 << std::endl;
}
Output
2018-Dec-19 vs. 2018-Nov-19

9.2. Добавление времени к календарю

#include <iostream>

#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

int main()
{
    namespace bp = boost::posix_time;
    namespace bg = boost::gregorian;

    bp::ptime pt{bg::date{2014, 5, 12}, bp::time_duration{12, 0, 0}};
    bp::time_iterator it{pt, bp::time_duration{6, 30, 0}};
    std::cout << *++it << "\n" << *++it << std::endl;
}
Output
2014-May-12 18:30:00
2014-May-13 01:00:00

9.3. Chrono

#include <iostream>

#include <boost/chrono.hpp>

int main()
{
    namespace bc = boost::chrono;

    auto p = bc::process_real_cpu_clock::now();
    std::cout << p << "\n"
              << bc::time_point_cast<bc::minutes>(p) << std::endl;
}
Output
17180161340000000 nanoseconds since process start-up
286336 minutes since process start-up

9.4. Таймер

#include <iostream>
#include <cmath>

#include <boost/timer/timer.hpp>

int main()
{
    boost::timer::auto_cpu_timer timer;
    for (int i = 0; i < 1000000; ++i)
        std::pow(1.234, i);

    std::cout << "Done\n";
}
Output
Done
 0.017470s wall, 0.010000s user + 0.000000s system = 0.010000s CPU (57.2%)

10. Функциональное программирование

10.1. Phoenix

» 10.1. (продолжение)

#include <iostream>

#include <boost/phoenix/phoenix.hpp>

int main()
{
    using namespace boost::phoenix::placeholders;

    std::vector v{{1, 2, 3, 4, 5}};
    std::for_each(v.begin(), v.end(), std::cout << arg1 << ",");
}
Output
1,2,3,4,5,

10.2. Функциональные объекты

10.3. Lambda

#include <algorithm>
#include <iostream>
#include <vector>

#include <boost/lambda/lambda.hpp>
#include <boost/lambda/if.hpp>

int main()
{
    std::vector v{{1, 3, 2}};
    std::for_each(v.begin(), v.end(),
        boost::lambda::if_then(boost::lambda::_1 > 1, std::cout << boost::lambda::_1 << "\n")
    );
}
Output
3
2

11. Параллельное программирование

11.1. Потоки

» 11.1. (продолжение)

#include <iostream>
#include <memory>
#include <mutex>
#include <thread>

#include <boost/thread/tss.hpp>

int main(int argc, const char**)
{
    std::mutex mutex;

    auto helper = [](auto& ptr) {
        if (!ptr.get())
        {
            ptr.reset(new bool{true});
            std::cout << "done" << '\n';
        }
    };

    auto worker = [&mutex, &helper, flag = argc > 1]() {
        static boost::thread_specific_ptr<bool> ptr1;
        static std::shared_ptr<bool> ptr2;
        std::lock_guard lock{mutex};
        if (flag)
            helper(ptr2);
        else
            helper(ptr1);
    };

    std::thread t[] = {std::thread{worker}, std::thread{worker}, std::thread{worker}};
    for (auto& x : t)
        x.join();
}
Output boost::thread_specific_ptr
done
done
done
Output shared_ptr
done

11.2. Atomic

11.3. Lockfree

» 11.3. (продолжение)

#include <atomic>
#include <future>
#include <iostream>
#include <thread>

#include <boost/lockfree/queue.hpp>

int main()
{
    boost::lockfree::queue<int> q(100);
    std::atomic<int> sum = 0;

    auto produce = [&q]() {
        for (int i = 1; i <= 100; ++i)
        {
            q.push(i);
            std::this_thread::yield();
        }
    };

    std::function<int(decltype(sum)&)> consume = [&q](auto& x) {
        int count = 0;
        while (q.consume_one([&x](int i){ x += i; }))
            ++count;
        return count;
    };

    std::thread t1{produce};
    auto t2 = std::async(consume, std::ref(sum));
    auto t3 = std::async(consume, std::ref(sum));
    t1.join();

    std::cout << "Thread2 count " << t2.get() << "\n"
              << "Thread3 count " << t3.get() << "\n"
              << "Sum " << sum << "\n";
    q.consume_all([&sum](int i){ sum += i; });
    std::cout << sum << std::endl;
}
Output
Thread2 count 46
Thread3 count 5
Sum 1326
5050

11.4. MPI

» 11.4. (продолжение)

» 11.4. (продолжение)

#include <algorithm>
#include <iostream>
#include <string>

#include <boost/mpi.hpp>

int main(int argc, char* argv[])
{
    boost::mpi::environment env{argc, argv};
    boost::mpi::communicator world;

    std::string s = "Hello, others!";
    if (world.rank() == 0)
        s = "Hello, world!";
    else if (world.rank() == 1)
        s = "Hello, moon!";
    else if (world.rank() == 2)
        s = "Hello, sun!";

    std::cout << "I am process " << world.rank()
              << " on " << world.size() << ", my value is [" << s << "]\n";

    std::string result;
    boost::mpi::reduce(world, s, result, [](const auto&... xs) { return std::min(xs...); }, 0);
    if (world.rank() == 0)
        std::cout << "The alphabet lowest output is [" << result << "]\n";
}
Output mpirun ./example10-3
I am process 1 on 2, my value is [Hello, moon!]
I am process 0 on 2, my value is [Hello, world!]
The alphabet lowest output is [Hello, moon!]

12. Обобщённое программирование

12.1. Type traits

12.2. Fusion

auto m = make_map<uint8_t, uint16_t, uint32_t>("Boost", 10, 3.14);
if (has_key<uint16_t>(m))
    std::cout << at_key<uint16_t>(m) << std::endl;

13. Языковые расширения

13.1. Coroutine

» 13.1. (продолжение)

#include <iostream>
#include <string>
#include <tuple>

#include <boost/coroutine2/coroutine.hpp>

int main()
{
    namespace bc2 = boost::coroutines2;

    auto cooperative = [](bc2::coroutine<std::tuple<int, std::string>>::pull_type &source) {
        auto args = source.get();
        std::cout << "first = " << std::get<0>(args) << " " << std::get<1>(args) << "\n";
        source();
        args = source.get();
        std::cout << "second = " << std::get<0>(args) << " " << std::get<1>(args) << "\n";
    };

    bc2::coroutine<std::tuple<int, std::string>>::push_type sink{cooperative};
    std::cout << "start: ";
    sink(std::make_tuple(0, "aaa"));
    std::cout << "next: ";
    sink(std::make_tuple(1, "bbb"));
    std::cout << "end\n";
}
Output
start: first = 0 aaa
next: second = 1 bbb
end

13.2. Parameter

#include <iostream>
#include <string>

#include <boost/parameter.hpp>

BOOST_PARAMETER_NAME(a)
BOOST_PARAMETER_NAME(b)
BOOST_PARAMETER_NAME(c)
BOOST_PARAMETER_NAME(d)
BOOST_PARAMETER_NAME(e)

BOOST_PARAMETER_FUNCTION(
    (void),
    complicated,
    tag,
    (required
        (a, (int))
        (b, (char)))
    (optional
        (c, (double), 3.14)
        (d, (std::string), "Boost")
        (e, *, true))
)
{
    std::cout.setf(std::ios::boolalpha);
    std::cout << a << '\n';
    std::cout << b << '\n';
    std::cout << c << '\n';
    std::cout << d << '\n';
    std::cout << e << '\n';
}

int main()
{
    complicated(_b = 'B', _a = 1, _d = "lala");
}
Output
1
B
3.14
lala
true

13.3. Conversion

#include <iostream>

#include <boost/cast.hpp>

struct base1 { virtual ~base1() = default; };
struct base2 { virtual ~base2() = default; };
struct derived : public base1, public base2 {};

void downcast(base1 *b1)
{
    derived* d = boost::polymorphic_downcast<derived*>(b1);
    std::cout << d << "\n";
}

void crosscast(base1 *b1)
{
    base2* b2 = boost::polymorphic_cast<base2*>(b1);
    std::cout << b2 << "\n";
}

int main()
{
    derived* d = new derived;
    downcast(d);

    base1* b1 = new derived;
    crosscast(b1);
}
Output
0x2088eb0
0x2089ee8

14. Обработка ошибок

14.1. System

#include <iostream>
#include <system_error>

int main()
{
    try
    {
        throw std::system_error{std::make_error_code(std::errc::not_supported)};
    }
    catch (const std::system_error& e)
    {
        std::error_code ec = e.code();
        std::cerr << ec.value() << '\n';
        std::cerr << ec.category().name() << std::endl;
    }
}
Output
95
generic

14.2. Исключения

    1: #include <iostream>
    2: #include <string>
    3: #include <stdexcept>
    4:
    5: #include <boost/exception/all.hpp>
    6:
    7: int main()
    8: {
    9:     using errmsg_info = boost::error_info<struct tag_errmsg, std::string>;
   10:
   11:     try
   12:     {
   13:         try
   14:         {
   15:             BOOST_THROW_EXCEPTION(std::runtime_error{"123"});
   16:         }
   17:         catch (const boost::exception& e)
   18:         {
   19:             e << errmsg_info{"writing lots of zeros failed"};
   20:             throw;
   21:         }
   22:     }
   23:     catch (const boost::exception& e)
   24:     {
   25:         std::cerr << *boost::get_error_info<errmsg_info>(e);
   26:         std::cerr << boost::diagnostic_information(e);
   27:     }
   28: }
Output
writing lots of zeros failed/home/runner/work/master-programming/master-programming/lecture-9/example13-2.cpp(15): Throw in function int main()
Dynamic exception type: boost::wrapexcept<std::runtime_error>
std::exception::what: 123
[main::tag_errmsg*] = writing lots of zeros failed

15. Работа с числами

15.1. Аккумуляторы

#include <iostream>

#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics.hpp>

int main()
{
    namespace ba = boost::accumulators;

    ba::accumulator_set<double, ba::features<ba::tag::mean, ba::tag::variance>, int> acc;
    acc(8, ba::weight=1);
    acc(9, ba::weight=1);
    acc(10, ba::weight=4);
    acc(11, ba::weight=1);
    acc(12, ba::weight=1);
    std::cout << ba::mean(acc) << ":" << ba::variance(acc) << std::endl;
}
Output
10:1.25

15.2. Преобразование чисел

#include <iostream>

#include <boost/numeric/conversion/cast.hpp>

int main()
{
    try
    {
        int i = 0x10000;
        short s = boost::numeric_cast<short>(i);
        std::cout << s << std::endl;
    }
    catch (boost::numeric::bad_numeric_cast &e)
    {
        std::cout << e.what() << std::endl;
    }
}
Output
bad numeric conversion: positive overflow

15.3. Что уже вошло в STL

16. Библиотеки для работы с приложением

16.1. Логирование

» 16.1. (продолжение)

#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/sinks/text_file_backend.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>

#include <boost/dll/runtime_symbol_info.hpp>

namespace bg = boost::log;

void init()
{
    auto exe_path = boost::dll::program_location();

    bg::add_file_log
    (
        bg::keywords::file_name=exe_path.parent_path() / "sample_%N.log", // <1>
        bg::keywords::rotation_size=10 * 1024 * 1024, // <2>
        bg::keywords::time_based_rotation=bg::sinks::file::rotation_at_time_point(0, 0, 0), // <3>
        bg::keywords::format="[%TimeStamp%]: %Message%" // <4>
    );

    bg::core::get()->set_filter(bg::trivial::severity >= bg::trivial::info);

    bg::add_common_attributes(); // <5>
}

int main()
{
    init();

    BOOST_LOG_TRIVIAL(trace) << "A trace severity message";
    BOOST_LOG_TRIVIAL(debug) << "A debug severity message";
    BOOST_LOG_TRIVIAL(info) << "An informational severity message";
    BOOST_LOG_TRIVIAL(warning) << "A warning severity message";
    BOOST_LOG_TRIVIAL(error) << "An error severity message";
    BOOST_LOG_TRIVIAL(fatal) << "A fatal severity message";
}
  1. Паттерн имени лога

  2. Условие размера лога при ротации

  3. Возможна также ротация по времени, например, в полночь

  4. Формат сообщений, которые будем видеть в логах

  5. Включение общих атрибутов, например, %TimeStamp%

Output
$ ./example15-1

$ cat ./sample_0.log
[2023-12-18 06:03:59.426792]: An informational severity message
[2023-12-18 06:03:59.426926]: A warning severity message
[2023-12-18 06:03:59.426937]: An error severity message
[2023-12-18 06:03:59.426943]: A fatal severity message

16.2. Аргументы командной строки

» 16.2. (продолжение)

#include <fstream>
#include <iostream>
#include <string>

#include <boost/program_options.hpp>

int main(int argc, char** argv)
{
    namespace po = boost::program_options;

    po::options_description generalOptions{"General"};
    generalOptions.add_options()
        ("help,h", "Help screen")
        ("config", po::value<std::string>()->default_value("/etc/config.cfg"), "Config file")
        ("age", po::value<int>(), "Age");

    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, generalOptions), vm);
    if (vm.count("config"))
    {
        std::ifstream ifs{vm["config"].as<std::string>()};
        if (ifs)
            po::store(po::parse_config_file(ifs, generalOptions), vm);
    }
    po::notify(vm);

    if (vm.count("help"))
        std::cout << generalOptions << std::endl;
    else if (vm.count("age"))
        std::cout << "Your age is: " << vm["age"].as<int>() << std::endl;
}
Output
$ ./example15-2 -h
General:
  -h [ --help ]                   Help screen
  --config arg (=/etc/config.cfg) Config file
  --age arg                       Age

$ ./example15-2 --age 21
Your age is: 21
$ ./example15-2 --config <(echo age = 22)
Your age is: 22

16.3. Сериализация

» 16.3. (продолжение)

» 16.3. (продолжение)

#include <iostream>
#include <sstream>

#include <boost/serialization/base_object.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

class animal
{
public:
    animal(int legs = 0) : legs_{legs} {}
    int legs() const { return legs_; }

private:
    friend class boost::serialization::access;

    template <typename Archive>
    void serialize(Archive &ar, const unsigned int /*version*/) { ar & legs_; }

    int legs_;
};

class bird : public animal
{
public:
    bird(bool can_fly = true) : animal{2}, can_fly_{can_fly} {}
    bool can_fly() const { return can_fly_; }

private:
    friend class boost::serialization::access;

    template <typename Archive>
    void serialize(Archive &ar, const unsigned int /*version*/)
    {
        ar & boost::serialization::base_object<animal>(*this);
        ar & can_fly_;
    }

    bool can_fly_;
};

int main()
{
    std::stringstream ss;

    auto serialize = [](auto& os, const bird& obj) {
        boost::archive::text_oarchive oa{os};
        oa << obj;
    };

    auto deserialize = [](auto& is) {
        boost::archive::text_iarchive ia{is};
        bird obj;
        ia >> obj;
        return obj;
    };

    bird penguin{false};
    serialize(ss, penguin);

    bird b = deserialize(ss);
    std::cout << b.legs() << " " << std::boolalpha << b.can_fly() << std::endl;
}
Output
2 false

16.4. UUID

» 16.4. (продолжение)

#include <iostream>

#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>

int main()
{
    boost::uuids::string_generator string_gen;
    boost::uuids::uuid id = string_gen("CF77C981-F61B-7817-10FF-D916FCC3EAA4");
    std::cout << id.variant() << ":" << id.version() << " = " << id << std::endl;
}
Output
0:-1 = cf77c981-f61b-7817-10ff-d916fcc3eaa4

17. Дизайн паттерны

17.1. Легковес

» 17.1. (продолжение)

#include <iostream>
#include <string>
#include <vector>

#include <boost/flyweight.hpp>

struct person
{
    struct country {};

    int id;
    boost::flyweight<std::string> city;
    boost::flyweight<std::string, boost::flyweights::tag<country>> country;

    person(int id, std::string city, std::string country)
        : id{id}, city{std::move(city)}, country{std::move(country)} {}
};

int main()
{
    std::vector<person> persons;
    for (int i = 0; i < 100000; ++i)
        persons.push_back({i, "Berlin", "Germany"});

    std::cout << "100th: " << persons[100].city << " " << &persons[100].city.get() << "\n"
              << "200th: " << persons[200].city << " " << &persons[200].city.get() << "\n";
}
Output
100th: Berlin 0xe4f2d0
200th: Berlin 0xe4f2d0

17.2. Signals2

» 17.2. (продолжение)

#include <iostream>

#include <boost/signals2.hpp>

int main()
{
    boost::signals2::signal<void()> s;

    auto hello = [] {
        std::cout << "Hello, world!" << std::endl;
    };

    auto disconnect = [&s, hello] {
        s.disconnect(hello);
    };

    s.connect(hello);
    s.connect(disconnect);
    s();
    s();
}
Output
Hello, world!

17.3. Машина состояний

» 17.3. (продолжение)

#include <iostream>
#include <type_traits>

#include <boost/msm/front/euml/euml.hpp>
#include <boost/msm/front/euml/state_grammar.hpp>
#include <boost/msm/back/state_machine.hpp>

using namespace boost::msm::front::euml;

BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int, switched_on)

BOOST_MSM_EUML_STATE((), Off)
BOOST_MSM_EUML_STATE((), On)

BOOST_MSM_EUML_EVENT(press)

BOOST_MSM_EUML_ACTION(WriteMessage)
{
    template<class Evt, class Fsm, class SourceState, class TargetState>
    void operator()(const Evt&, Fsm&, const SourceState&, const TargetState&)
    {
        if constexpr (std::is_same_v<SourceState, decltype(Off)>)
            std::cout << "Switched on\n";
        else
            std::cout << "Switched off\n";
    }
};

BOOST_MSM_EUML_TRANSITION_TABLE((
    Off + press [fsm_(switched_on) < Int_<2>()] / (++fsm_(switched_on), WriteMessage()) == On,
    On + press / WriteMessage() == Off
), light_transition_table)

BOOST_MSM_EUML_DECLARE_STATE_MACHINE((
    light_transition_table, init_ << Off, no_action, no_action, attributes_ << switched_on
), light_state_machine)

int main()
{
    boost::msm::back::state_machine<light_state_machine> light;
    std::cout << "Current state: " << *(light.current_state()) << "\n";
    light.process_event(press);
    std::cout << "Current state: " << *(light.current_state()) << "\n";
    light.process_event(press);
    std::cout << "Current state: " << *(light.current_state()) << "\n";
    light.process_event(press);
    std::cout << "Current state: " << *(light.current_state()) << "\n";
    light.process_event(press);
    std::cout << "Current state: " << *(light.current_state()) << "\n";
    light.process_event(press);
    std::cout << "Current state: " << *(light.current_state()) << "\n";
}
Output
Current state: 0
Switched on
Current state: 1
Switched off
Current state: 0
Switched on
Current state: 1
Switched off
Current state: 0
Current state: 0

18. Другие библиотеки

18.1. Utility

18.2. Assign

std::vector<std::pair<std::string, int>> v = boost::assign::list_of<std::pair<std::string, int>>("a", 1)("b", 2)("c", 3);

std::vector<int> v2;
boost::assign::push_back(v2)(1)(2)(3);

using namespace boost::assign;

vector<int> values;
values += 1,2,3,4,5,6,7,8,9;

18.3. Операторы

class MyInt : boost::operators<MyInt>
{
    bool operator<(const MyInt& x) const;
    bool operator==(const MyInt& x) const;
    MyInt& operator+=(const MyInt& x);
    MyInt& operator-=(const MyInt& x);
    MyInt& operator*=(const MyInt& x);
    MyInt& operator/=(const MyInt& x);
    MyInt& operator%=(const MyInt& x);
    MyInt& operator|=(const MyInt& x);
    MyInt& operator&=(const MyInt& x);
    MyInt& operator^=(const MyInt& x);
    MyInt& operator++();
    MyInt& operator--();
};