Михаил Матросов, Повседневный С++: boost и stl

63
Повседневный С++: boost и STL Михаил Матросов [email protected] [email protected] 1

Upload: sergey-platonov

Post on 06-Jan-2017

1.211 views

Category:

Software


3 download

TRANSCRIPT

Page 1: Михаил Матросов, Повседневный С++: boost и STL

Повседневный С++: boost и STL

Михаил Матросов[email protected]

[email protected]

1

Page 2: Михаил Матросов, Повседневный С++: boost и STL

2

Page 3: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 3

Page 4: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 4

С++17С++11/14

С++98

С

High level

Expert level

Modern C++

Page 5: Михаил Матросов, Повседневный С++: boost и STL

“Within C++ is a smaller, simpler, safer language struggling to get out”

Bjarne Stroustrup

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 5

Page 6: Михаил Матросов, Повседневный С++: boost и STL

High level: Парадигма RAII и исключения (exceptions) Алгоритмы и контейнеры STL и boost Семантика перемещения λ-функции Классы и конструкторы Простые шаблоны

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 6

Expert level: Операторы new/delete, владеющие

указатели Пользовательские операции копирования

и перемещения Пользовательские деструкторы Закрытое, защищённое, ромбовидное,

виртуальное наследование Шаблонная магия, SFINAE Все функции языка Си, препроцессор «Голые» циклы

Классический слайд с телом и заголовком

Page 8: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 8

bool doCompare(const Bakery* oldBakery, const Bakery* newBakery){  if (!oldBakery || !newBakery)  {    return false;  }   std::vector<Cookie> oldCookies;  std::vector<Cookie> newCookies;  std::vector<std::pair<Cookie, int>> diff;   collectCookies(*oldBakery, oldCookies);  collectCookies(*newBakery, newCookies);   std::sort(oldCookies.begin(), oldCookies.end(), compareCookies);  std::sort(newCookies.begin(), newCookies.end(), compareCookies);   auto oldIt = oldCookies.begin();  auto newIt = newCookies.begin();   while ((oldIt != oldCookies.end()) || (newIt != newCookies.end()))  {    if (compareCookies(*oldIt, *newIt))    {      diff.push_back(std::pair<Cookie, int>(*oldIt, 1));      ++oldIt;    }    else if (compareCookies(*newIt, *oldIt))    {      diff.push_back(std::pair<Cookie, int>(*newIt, 2));      ++newIt;    }    else    {      ++oldIt;      ++newIt;    }  }   if (oldIt != oldCookies.end())  {    for (; oldIt < oldCookies.end(); oldIt++)    {      diff.push_back(std::pair<Cookie, int>(*oldIt, 1));    }  }   if (newIt != newCookies.end())  {    for (; newIt < newCookies.end(); newIt++)    {      diff.push_back(std::pair<Cookie, int>(*newIt, 2));    }  }   for (const auto& item : diff)  {    std::cout << "Bakery #" << item.second <<      " has a different cookie \"" << item.first.name <<       "\" (weight=" << item.first.weight <<      ", volume=" << item.first.volume <<       ", tastiness=" << item.first.tastiness << ")." << std::endl;  }   if (diff.size() > 0)    return false;  return true;}

Page 9: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 9

bool doCompare(const Bakery* oldBakery, const Bakery* newBakery){  if (!oldBakery || !newBakery)  {    return false;  }   std::vector<Cookie> oldCookies;  std::vector<Cookie> newCookies;   collectCookies(*oldBakery, oldCookies);  collectCookies(*newBakery, newCookies);   std::sort(oldCookies.begin(), oldCookies.end(), compareCookies);  std::sort(newCookies.begin(), newCookies.end(), compareCookies);   auto oldIt = oldCookies.begin();  auto newIt = newCookies.begin();   std::vector<std::pair<Cookie, int>> diff;

  while ((oldIt != oldCookies.end()) || (newIt != newCookies.end()))  {    if (compareCookies(*oldIt, *newIt))    {      diff.push_back(std::pair<Cookie, int>(*oldIt, 1));      ++oldIt;    }    else if (compareCookies(*newIt, *oldIt))    {      diff.push_back(std::pair<Cookie, int>(*newIt, 2));      ++newIt;    }    else    {      ++oldIt;      ++newIt;    }  }   if (oldIt != oldCookies.end())  {    for (; oldIt < oldCookies.end(); oldIt++)    {      diff.push_back(std::pair<Cookie, int>(*oldIt, 1));    }  }   if (newIt != newCookies.end())  {    for (; newIt < newCookies.end(); newIt++)    {      diff.push_back(std::pair<Cookie, int>(*newIt, 2));    }  }   for (const auto& item : diff)  {    std::cout << "Bakery #" << item.second <<      " has a different cookie \"" << item.first.name <<       "\" (weight=" << item.first.weight <<      ", volume=" << item.first.volume <<       ", tastiness=" << item.first.tastiness << ")." << std::endl;  }   if (diff.size() > 0)    return false;  return true;}

bool doCompare(const Bakery& oldBakery, const Bakery& newBakery){  std::vector<Cookie> oldCookies = collectSortedCookies(oldBakery);  std::vector<Cookie> newCookies = collectSortedCookies(newBakery);   std::vector<Cookie> lostCookies;  boost::range::set_difference(oldCookies, newCookies, std::back_inserter(lostCookies));   std::vector<Cookie> appearedCookies;  boost::range::set_difference(newCookies, oldCookies, std::back_inserter(appearedCookies));   for (const auto& cookie : lostCookies)  {    std::cout << "We've lost a friend: " << cookie << "." << std::endl;  }  for (const auto& cookie : appearedCookies)  {    std::cout << "We got a new friend: " << cookie << "." << std::endl;  }   return lostCookies.empty() && appearedCookies.empty();}

Page 10: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 10

bool doCompare(const Bakery* oldBakery, const Bakery* newBakery){  if (!oldBakery || !newBakery)  {    return false;  }   std::vector<Cookie> oldCookies;  std::vector<Cookie> newCookies;   collectCookies(*oldBakery, oldCookies);  collectCookies(*newBakery, newCookies); // ...

Page 11: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 11

bool doCompare(const Bakery& oldBakery, const Bakery& newBakery){

  std::vector<Cookie> oldCookies;  std::vector<Cookie> newCookies;   collectCookies(oldBakery, oldCookies);  collectCookies(newBakery, newCookies); // ...

Page 12: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 12

Page 13: Михаил Матросов, Повседневный С++: boost и STL

bool doCompare(const Bakery& oldBakery, const Bakery& newBakery){  std::vector<Cookie> oldCookies;  std::vector<Cookie> newCookies;   collectCookies(oldBakery, oldCookies);  collectCookies(newBakery, newCookies); // ...

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 13

Page 14: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 14

void collectCookies(const Bakery& bakery, std::vector<Cookie>& o_cookies); bool doCompare(const Bakery& oldBakery, const Bakery& newBakery){  std::vector<Cookie> oldCookies;  std::vector<Cookie> newCookies;   collectCookies(oldBakery, oldCookies);  collectCookies(newBakery, newCookies); // ...

Page 15: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 15

std::vector<Cookie> collectCookies(const Bakery& bakery);

bool doCompare(const Bakery& oldBakery, const Bakery& newBakery){ std::vector<Cookie> oldCookies = collectCookies(oldBakery); std::vector<Cookie> newCookies = collectCookies(newBakery);

// ...

In-depth: Functional programming in C++

Page 16: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 16

λλ=:

Page 17: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 17

// ... std::sort(oldCookies.begin(), oldCookies.end(), compareCookies);  std::sort(newCookies.begin(), newCookies.end(), compareCookies);

  auto oldIt = oldCookies.begin();  auto newIt = newCookies.begin();  std::vector<std::pair<Cookie, int>> diff;

  while ((oldIt != oldCookies.end()) || (newIt != newCookies.end()))  {    if (compareCookies(*oldIt, *newIt))    {      diff.push_back(std::pair<Cookie, int>(*oldIt, 1));      ++oldIt;    }    else if (compareCookies(*newIt, *oldIt))    { // ...

Page 18: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 18

struct Cookie{  double weight;  double volume;  std::string name;  int tastiness;}; bool compareCookies(const Cookie& a, const Cookie& b){  if (a.tastiness != b.tastiness)    return a.tastiness < b.tastiness;   if (a.weight != b.weight)    return a.weight < b.weight;   if (a.volume != b.volume)    return a.volume < b.volume;   return a.name < b.name;}

Page 19: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 19

struct Cookie{  double weight;  double volume;  std::string name;  int tastiness;}; bool operator<(const Cookie& a, const Cookie& b){  if (a.tastiness != b.tastiness)    return a.tastiness < b.tastiness;   if (a.weight != b.weight)    return a.weight < b.weight;   if (a.volume != b.volume)    return a.volume < b.volume;   return a.name < b.name;}

Page 20: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 20

// ... std::sort(oldCookies.begin(), oldCookies.end(), compareCookies);  std::sort(newCookies.begin(), newCookies.end(), compareCookies);   auto oldIt = oldCookies.begin();  auto newIt = newCookies.begin();   while ((oldIt != oldCookies.end()) || (newIt != newCookies.end()))  {    if (compareCookies(*oldIt, *newIt))    {      diff.push_back(std::pair<Cookie, int>(*oldIt, 1));      ++oldIt;    }    else if (compareCookies(*newIt, *oldIt))    { // ...

Page 21: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 21

// ... std::sort(oldCookies.begin(), oldCookies.end());  std::sort(newCookies.begin(), newCookies.end());   auto oldIt = oldCookies.begin();  auto newIt = newCookies.begin();   while ((oldIt != oldCookies.end()) || (newIt != newCookies.end()))  {    if (*oldIt < *newIt)    {      diff.push_back(std::pair<Cookie, int>(*oldIt, 1));      ++oldIt;    }    else if (*newIt < *oldIt)    { // ...

Page 22: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 22

bool operator<(const Cookie& a, const Cookie& b){  if (a.tastiness != b.tastiness)    return a.tastiness < b.tastiness;   if (a.weight != b.weight)    return a.weight < b.weight;   if (a.volume != b.volume)    return a.volume < b.volume;   return a.name < b.name;}

Page 23: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 23

bool operator<(const Cookie& a, const Cookie& b){ return std::make_tuple(a.tastiness, a.weight, a.volume, a.name) <         std::make_tuple(b.tastiness, b.weight, b.volume, b.name); }

Page 24: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 24

struct Cookie{  double weight;  double volume;  std::string name;  int tastiness;}; bool operator<(const Cookie& a, const Cookie& b){ return std::make_tuple(a.tastiness, a.weight, a.volume, a.name) <         std::make_tuple(b.tastiness, b.weight, b.volume, b.name); }

Page 25: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 25

struct Cookie{  double weight;  double volume;  std::string name;  int tastiness;}; bool operator<(const Cookie& a, const Cookie& b){ return std::tie(a.tastiness, a.weight, a.volume, a.name) <         std::tie(b.tastiness, b.weight, b.volume, b.name); }

Page 26: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 26

struct Cookie{  double weight;  double volume;  std::string name;  int tastiness;

auto rank() const {   return std::tie(tastiness, weight, volume, name); } }; bool operator<(const Cookie& a, const Cookie& b){ return a.rank() < b.rank();}

Implementing comparison operators via 'tuple' and 'tie', a good idea?

Page 27: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 27

struct Cookie{  double weight;  double volume;  std::string name;  int tastiness;

auto rank() const // -> std::tuple<const int&, const double&, { // const double&, const std::string&>   return std::tie(tastiness, weight, volume, name); } }; bool operator<(const Cookie& a, const Cookie& b){ return a.rank() < b.rank();}

Implementing comparison operators via 'tuple' and 'tie', a good idea?

Page 28: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 28

struct Cookie{  double weight;  double volume;  std::string name;  int tastiness;

auto rank() const // -> std::tuple<const int&, const double&, { // const double&, const std::string&>   return std::tie(tastiness, weight, volume, name); } }; bool operator<(const Cookie& a, const Cookie& b){ return a.rank() < b.rank();}bool operator==(const Cookie& a, const Cookie& b){ return a.rank() == b.rank();}

Page 29: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 29

Page 30: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 30

bool doCompare(const Bakery& oldBakery, const Bakery& newBakery){  std::vector<Cookie> oldCookies = collectCookies(oldBakery);  std::vector<Cookie> newCookies = collectCookies(newBakery);   std::sort(oldCookies.begin(), oldCookies.end());  std::sort(newCookies.begin(), newCookies.end());

// ...

Page 31: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 31

std::vector<Cookie> collectCookies(const Bakery& bakery){  std::vector<Cookie> cookies;  // ...  // ...  return cookies;} bool doCompare(const Bakery& oldBakery, const Bakery& newBakery){  std::vector<Cookie> oldCookies = collectCookies(oldBakery);  std::vector<Cookie> newCookies = collectCookies(newBakery);   std::sort(oldCookies.begin(), oldCookies.end());  std::sort(newCookies.begin(), newCookies.end());

// ...

Page 32: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 32

std::vector<Cookie> collectSortedCookies(const Bakery& bakery){  std::vector<Cookie> cookies;  // ...  std::sort(cookies.begin(), cookies.end());  return cookies;} bool doCompare(const Bakery& oldBakery, const Bakery& newBakery){  std::vector<Cookie> oldCookies = collectSortedCookies(oldBakery);  std::vector<Cookie> newCookies = collectSortedCookies(newBakery);

// ...

Page 33: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 33

Page 34: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 34

std::vector<std::pair<Cookie, int>> diff;

// ...

if (*oldIt < *newIt){  diff.push_back(std::pair<Cookie, int>(*oldIt, 1));  ++oldIt;}else if (*newIt < *oldIt){  diff.push_back(std::pair<Cookie, int>(*newIt, 2));  ++newIt;}

Page 35: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 35

std::vector<std::pair<Cookie, int>> diff;

// ...

if (*oldIt < *newIt){  diff.push_back(std::make_pair(*oldIt, 1));  ++oldIt;}else if (*newIt < *oldIt){  diff.push_back(std::make_pair(*newIt, 2));  ++newIt;}

Page 36: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 36

std::vector<std::pair<Cookie, int>> diff;

// ...

if (*oldIt < *newIt){  diff.push_back({ *oldIt, 1 });  ++oldIt;}else if (*newIt < *oldIt){  diff.push_back({ *newIt, 2 });  ++newIt;}

Page 37: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 37

std::vector<std::pair<Cookie, int>> diff;

// ...

if (*oldIt < *newIt){  diff.emplace_back(*oldIt, 1);  ++oldIt;}else if (*newIt < *oldIt){  diff.emplace_back(*newIt, 2);  ++newIt;}

Page 38: Михаил Матросов, Повседневный С++: boost и STL

for (const auto& item : diff) // item is std::pair<Cookie, int>{  std::cout << "Bakery #" << item.second <<    " has a different cookie \"" << item.first.name <<     "\" (weight=" << item.first.weight <<    ", volume=" << item.first.volume <<     ", tastiness=" << item.first.tastiness << ")." << std::endl;}

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 38

Page 39: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 39

for (const auto& item : diff) // item is std::pair<Cookie, int>{  std::cout << "Bakery #" << item.second <<   " has a different cookie " << item.first << "." << std::endl;}

std::ostream& operator<<(std::ostream& stream, const Cookie& cookie){  return stream << "\"" << cookie.name <<    "\" (weight=" << cookie.weight <<    ", volume=" << cookie.volume <<    ", tastiness=" << cookie.tastiness << ")";}

Page 40: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 40

if (diff.size() > 0)  return false;return true;

Page 41: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 41

return diff.empty();

Page 42: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 42

Page 43: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 43

auto oldIt = oldCookies.begin();auto newIt = newCookies.begin(); std::vector<std::pair<Cookie, int>> diff; while ((oldIt != oldCookies.end()) || (newIt != newCookies.end())){  if (*oldIt < *newIt)  {    diff.emplace_back(*oldIt, 1);    ++oldIt;  }  else if (*newIt < *oldIt)  {    diff.emplace_back(*newIt, 2);    ++newIt;  }  else  {    ++oldIt;    ++newIt;  }} for (; oldIt != oldCookies.end(); oldIt++){  diff.emplace_back(*oldIt, 1);} for (; newIt != newCookies.end(); newIt++){  diff.emplace_back(*newIt, 2);}

1 2 5 7 8 9

1 3 5 6 9

2 7 83 6

oldCookies

newCookies

diff

Ошибка. Должно быть &&

Sean Parent: C++ Seasoning (no raw loops)

Page 44: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 44

Page 45: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 45

std::vector<Cookie> lostCookies; std::set_difference(oldCookies.begin(), oldCookies.end(),                      newCookies.begin(), newCookies.end(),                      std::back_inserter(lostCookies)); std::vector<Cookie> appearedCookies; std::set_difference(newCookies.begin(), newCookies.end(),                      oldCookies.begin(), oldCookies.end(),                                           std::back_inserter(appearedCookies));

Page 46: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 46

  std::vector<Cookie> lostCookies;  boost::range::set_difference(oldCookies, newCookies, std::back_inserter(lostCookies));   std::vector<Cookie> appearedCookies;  boost::range::set_difference(newCookies, oldCookies, std::back_inserter(appearedCookies));

Page 47: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 47

  std::vector<Cookie> lostCookies;  boost::range::set_difference(oldCookies, newCookies, std::back_inserter(lostCookies));   std::vector<Cookie> appearedCookies;  boost::range::set_difference(newCookies, oldCookies, std::back_inserter(appearedCookies));   for (const auto& cookie : lostCookies)  {    std::cout << "We've lost a friend: " << cookie << "." << std::endl;  }  for (const auto& cookie : appearedCookies)  {    std::cout << "We got a new friend: " << cookie << "." << std::endl;  }

Page 48: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 48

bool doCompare(const Bakery& oldBakery, const Bakery& newBakery){  std::vector<Cookie> oldCookies = collectSortedCookies(oldBakery);  std::vector<Cookie> newCookies = collectSortedCookies(newBakery);

  return lostCookies.empty() && appearedCookies.empty();}

  std::vector<Cookie> lostCookies;  boost::range::set_difference(oldCookies, newCookies, std::back_inserter(lostCookies));   std::vector<Cookie> appearedCookies;  boost::range::set_difference(newCookies, oldCookies, std::back_inserter(appearedCookies));   for (const auto& cookie : lostCookies)  {    std::cout << "We've lost a friend: " << cookie << "." << std::endl;  }  for (const auto& cookie : appearedCookies)  {    std::cout << "We got a new friend: " << cookie << "." << std::endl;  }

Page 49: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 49

bool doCompare(const Bakery* oldBakery, const Bakery* newBakery){  if (!oldBakery || !newBakery)  {    return false;  }   std::vector<Cookie> oldCookies;  std::vector<Cookie> newCookies;   collectCookies(*oldBakery, oldCookies);  collectCookies(*newBakery, newCookies);   std::sort(oldCookies.begin(), oldCookies.end(), compareCookies);  std::sort(newCookies.begin(), newCookies.end(), compareCookies);   auto oldIt = oldCookies.begin();  auto newIt = newCookies.begin();   std::vector<std::pair<Cookie, int>> diff;

  while ((oldIt != oldCookies.end()) || (newIt != newCookies.end()))  {    if (compareCookies(*oldIt, *newIt))    {      diff.push_back(std::pair<Cookie, int>(*oldIt, 1));      ++oldIt;    }    else if (compareCookies(*newIt, *oldIt))    {      diff.push_back(std::pair<Cookie, int>(*newIt, 2));      ++newIt;    }    else    {      ++oldIt;      ++newIt;    }  }   if (oldIt != oldCookies.end())  {    for (; oldIt < oldCookies.end(); oldIt++)    {      diff.push_back(std::pair<Cookie, int>(*oldIt, 1));    }  }   if (newIt != newCookies.end())  {    for (; newIt < newCookies.end(); newIt++)    {      diff.push_back(std::pair<Cookie, int>(*newIt, 2));    }  }   for (const auto& item : diff)  {    std::cout << "Bakery #" << item.second <<      " has a different cookie \"" << item.first.name <<       "\" (weight=" << item.first.weight <<      ", volume=" << item.first.volume <<       ", tastiness=" << item.first.tastiness << ")." << std::endl;  }   if (diff.size() > 0)    return false;  return true;}

bool doCompare(const Bakery& oldBakery, const Bakery& newBakery){  std::vector<Cookie> oldCookies = collectSortedCookies(oldBakery);  std::vector<Cookie> newCookies = collectSortedCookies(newBakery);   std::vector<Cookie> lostCookies;  boost::range::set_difference(oldCookies, newCookies, std::back_inserter(lostCookies));   std::vector<Cookie> appearedCookies;  boost::range::set_difference(newCookies, oldCookies, std::back_inserter(appearedCookies));   for (const auto& cookie : lostCookies)  {    std::cout << "We've lost a friend: " << cookie << "." << std::endl;  }  for (const auto& cookie : appearedCookies)  {    std::cout << "We got a new friend: " << cookie << "." << std::endl;  }   return lostCookies.empty() && appearedCookies.empty();}

Page 50: Михаил Матросов, Повседневный С++: boost и STL

Код, использующий стандартные алгоритмы и контейнеры:КорочеПрощеНадёжнееОбычно эффективнееПроще переиспользоватьНе привязан к конкретной платформе

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 50

Page 51: Михаил Матросов, Повседневный С++: boost и STL

И ещё немного по

теме…"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 51

Page 52: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 52

struct Cookie{  double weight;  double volume;  std::string name;  int tastiness;  auto rank() const {   return std::tie(tastiness, weight, volume, name); } };

Page 53: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 53

struct Cookie{  double weight;  double volume;  std::string name;  int tastiness; double density() const {   return weight / volume; } auto rank() const {   return std::tie(tastiness, density(), name); }};

Page 54: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 54

struct Cookie{  double weight;  double volume;  std::string name;  int tastiness; double density() const {   return weight / volume; } auto rank() const { return std::make_tuple(tastiness, density(), std::ref(name)); }};

Page 55: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 55

struct Cookie{  double weight;  double volume;  std::string name;  int tastiness; double density() const {   return weight / volume; } auto rank() const // -> std::tuple<int, double, const std::string&> { return std::make_tuple(tastiness, density(), std::ref(name)); }};

Page 56: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 56

std::vector<Cookie> lostCookies;boost::range::set_difference(oldCookies, newCookies, std::back_inserter(lostCookies)); std::vector<Cookie> appearedCookies;boost::range::set_difference(newCookies, oldCookies, std::back_inserter(appearedCookies));for (const auto& cookie : lostCookies){  std::cout << "We've lost a friend: " << cookie << "." << std::endl;}for (const auto& cookie : appearedCookies){  std::cout << "We got a new friend: " << cookie << "." << std::endl;}

Page 57: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 57

auto reportLost = [](const Cookie& cookie) {  std::cout << "We've lost a friend: " << cookie << "." << std::endl;};auto reportAppeared = [](const Cookie& cookie) {  std::cout << "We got a new friend: " << cookie << "." << std::endl;}; boost::range::set_difference(oldCookies, newCookies,  boost::make_function_output_iterator(reportLost));boost::range::set_difference(newCookies, oldCookies,  boost::make_function_output_iterator(reportAppeared));

Page 58: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 58

auto reportLost = [](const Cookie& cookie) {  std::cout << "We've lost a friend: " << cookie << "." << std::endl;};auto reportAppeared = [](const Cookie& cookie) {  std::cout << "We got a new friend: " << cookie << "." << std::endl;}; boost::range::set_difference(oldCookies, newCookies,  boost::make_function_output_iterator(reportLost));boost::range::set_difference(newCookies, oldCookies,  boost::make_function_output_iterator(reportAppeared));

return oldCookies == newCookies; // was "lostCookies.empty() && appearedCookies.empty()"

Page 59: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 59

auto f = [](int x) { std::cout << x; };auto it = boost::make_function_output_iterator(f);decltype(it) it2 = it;  // Ok, copiedit2 = it;  // Does not compile, cannot assign!

std::function<void(int)> f = [](int x) { std::cout << x; };auto it = boost::make_function_output_iterator(f);decltype(it) it2 = it;  // Ok, copiedit2 = it;  // Ok, iterator holds an std::function instance

auto f = [](int x) { std::cout << x; };auto it = boost::make_function_output_iterator(std::ref(f));decltype(it) it2 = it;  // Ok, copiedit2 = it;  // Ok, iterator holds a reference

auto f = +[](int x) { std::cout << x; };auto it = boost::make_function_output_iterator(f);decltype(it) it2 = it;  // Ok, copiedit2 = it;  // Ok, note the plus before [], it triggers special C++ magic

Resolving ambiguous overload on function pointer and std::function for a lambda using +

boost::function_output_iterator constructed from lambda function is not assignable

Page 60: Михаил Матросов, Повседневный С++: boost и STL

Советы:Мыслите на высоком уровнеКод должен ясно выражать намерениеЗнайте свои инструменты и используйте их к месту

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 60

// references// auto variables// auto function return type// move semantics// lambda functionsoperator<();std::make_tuple();std::tie();std::ref();

std::make_pair();std::vector<T>::emplace_back();std::vector<T>::empty();operator<<();std::back_inserter();std::set_difference();boost::range::set_difference();boost::make_function_output_iterator();std::function<>

Page 61: Михаил Матросов, Повседневный С++: boost и STL

Мыслите на высоком уровнеКод должен ясно выражать намерениеЗнайте свои инструменты и используйте их к месту

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016

std::make_pair();std::vector<T>::emplace_back();std::vector<T>::empty();operator<<();std::back_inserter();std::set_difference();boost::range::set_difference();boost::make_function_output_iterator();std::function<>

Спасибо за внимание!

// references// auto variables// auto function return type// move semantics// lambda functionsoperator<();std::make_tuple();std::tie();std::ref();

61

Page 62: Михаил Матросов, Повседневный С++: boost и STL

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 62

compareRanked(Cookie const&, Cookie const&): movl 16(%rsi), %edx cmpl %edx, 16(%rdi) movl $1, %eax jl .L2 movl $0, %eax jg .L2 movsd (%rdi), %xmm1 movl $1, %eax movsd (%rsi), %xmm0 ucomisd %xmm1, %xmm0 ja .L2 xorl %eax, %eax ucomisd %xmm0, %xmm1 ja .L2 movsd 8(%rsi), %xmm0 ucomisd 8(%rdi), %xmm0 seta %al.L2: rep ret

compareDirect(Cookie const&, Cookie const&): movl 16(%rsi), %eax cmpl %eax, 16(%rdi) je .L9 setl %al ret.L9: movsd (%rdi), %xmm0 movsd (%rsi), %xmm1 ucomisd %xmm1, %xmm0 jp .L13 jne .L13 movsd 8(%rsi), %xmm0 ucomisd 8(%rdi), %xmm0 seta %al ret.L13: ucomisd %xmm0, %xmm1 seta %al ret

Page 63: Михаил Матросов, Повседневный С++: boost и STL

Ссылки Which boost features overlap with C++11? In-depth: Functional programming in C++ Implementing comparison operators via 'tuple' and 'tie', a good idea? Sean Parent: C++ Seasoning (no raw loops) boost::function_output_iterator constructed from lambda function is not assignable Resolving ambiguous overload on function pointer and std::function for a lambda using +

"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 63