Михаил Матросов, Повседневный С++: boost и stl
TRANSCRIPT
2
"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 3
"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 4
С++17С++11/14
С++98
С
High level
Expert level
Modern C++
“Within C++ is a smaller, simpler, safer language struggling to get out”
Bjarne Stroustrup
"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 5
High level: Парадигма RAII и исключения (exceptions) Алгоритмы и контейнеры STL и boost Семантика перемещения λ-функции Классы и конструкторы Простые шаблоны
"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 6
Expert level: Операторы new/delete, владеющие
указатели Пользовательские операции копирования
и перемещения Пользовательские деструкторы Закрытое, защищённое, ромбовидное,
виртуальное наследование Шаблонная магия, SFINAE Все функции языка Си, препроцессор «Голые» циклы
Классический слайд с телом и заголовком
7
Which boost features overlap with C++11?
"Повседневный С++: 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;}
"Повседневный С++: 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();}
"Повседневный С++: 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); // ...
"Повседневный С++: 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); // ...
"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 12
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
"Повседневный С++: 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); // ...
"Повседневный С++: 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++
"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 16
λλ=:
"Повседневный С++: 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)) { // ...
"Повседневный С++: 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;}
"Повседневный С++: 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;}
"Повседневный С++: 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)) { // ...
"Повседневный С++: 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) { // ...
"Повседневный С++: 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;}
"Повседневный С++: 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); }
"Повседневный С++: 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); }
"Повседневный С++: 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); }
"Повседневный С++: 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?
"Повседневный С++: 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?
"Повседневный С++: 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();}
"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 29
"Повседневный С++: 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());
// ...
"Повседневный С++: 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());
// ...
"Повседневный С++: 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);
// ...
"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 33
"Повседневный С++: 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;}
"Повседневный С++: 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;}
"Повседневный С++: 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;}
"Повседневный С++: 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;}
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
"Повседневный С++: 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 << ")";}
"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 40
if (diff.size() > 0) return false;return true;
"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 41
return diff.empty();
"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 42
"Повседневный С++: 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)
"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 44
"Повседневный С++: 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));
"Повседневный С++: 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));
"Повседневный С++: 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; }
"Повседневный С++: 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; }
"Повседневный С++: 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();}
Код, использующий стандартные алгоритмы и контейнеры:КорочеПрощеНадёжнееОбычно эффективнееПроще переиспользоватьНе привязан к конкретной платформе
"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 50
И ещё немного по
теме…"Повседневный С++: boost и STL", Михаил Матросов, C++ Russia 2016 51
"Повседневный С++: 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); } };
"Повседневный С++: 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); }};
"Повседневный С++: 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)); }};
"Повседневный С++: 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)); }};
"Повседневный С++: 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;}
"Повседневный С++: 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));
"Повседневный С++: 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()"
"Повседневный С++: 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
Советы:Мыслите на высоком уровнеКод должен ясно выражать намерениеЗнайте свои инструменты и используйте их к месту
"Повседневный С++: 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<>
Мыслите на высоком уровнеКод должен ясно выражать намерениеЗнайте свои инструменты и используйте их к месту
"Повседневный С++: 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
"Повседневный С++: 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
Ссылки 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