воскресенье, 29 октября 2017 г.

[prog.c++] Какой код на С++11/14 произвел на вас самое большое впечатление?

В процессе подготовки доклада к GECon-2017 столкнулся с необходимостью привести небольшой, но яркий пример отличия кода на C++11/14 от кода на C++98. Пока в качестве примера я хочу привести код, который наполняет std::vector несколькими значениями, копирует оттуда те элементы, которые удовлетворяют некоторому условию в другой вектор, затем результирующий вектор сортируется и отображается через std::cout. В коде на С++98 это будет сделано через функторы и итераторы. В коде на C++11/14 это уже будет с initializer lists, лямбдами, туплами и range-for.

Однако, есть подозрение, что данный пример окажется слишком объемным и невыразительным. А это не есть хорошо.

К сожалению, с хорошими примерами происходит как с анекдотами: когда очень нужно, то хрен вспомнишь. А когда вспоминаешь, то вокруг уже никого нет.

Посему обращаюсь к читателям: есть ли у вас самые яркие впечатления от знакомства с C++11/14? Вот увидели какой-то код на C++11/14 и поняли, что C++ стал другим и то, что в С++98 требовало кучи приседаний, в C++11/14 записывается легко и непринужденно. Если есть, то не сочтите за труд, поделитесь, пожалуйста.

Upd. Под катом варианты, которые есть на данный момент.

Код для C++98/03:

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

using namespace std;

struct place {
   string name_;
   float price_;
   int rating_;

   place() {}
   place(const char * name, float price, int rating)
      : name_(name), price_(price), rating_(rating) {}
};

bool compare_by_rating_and_name(const place & a, const place & b) {
   return a.rating_ < b.rating_ || (a.rating_ == b.rating_ &&
         a.name_ < b.name_);
}

struct price_less_than {
   const float price_;
   price_less_than(float price) : price_(price) {}
   bool operator()(const place & p) { return p.price_ < price_; }
};

template<class In_It, class Out_It, class P>
Out_It copy_n_if(size_t n, In_It b, In_It e, Out_It to, P predicate)
{
   for(; n && b != e; ++b)
      if(predicate(*b)) { *to = *b; ++to; --n; }

   return to;
}

vector<place> fill_places() {
   vector<place> places;
   places.push_back(place("Moscow"15003));
   places.push_back(place("St. Petersburg"13005));
   places.push_back(place("Minsk"5004));
   places.push_back(place("Tokyo"35004));
   places.push_back(place("Sydney"50003));
   places.push_back(place("Paris"30005));
   return places;
}

int main() {
   const vector<place> places = fill_places();

   place result[10];
   place * result_end = copy_n_if(
         sizeof(result)/sizeof(result[0]),
         places.begin(), places.end(),
         result,
         price_less_than(4000));
   sort(result, result_end, compare_by_rating_and_name);

   for(place * i = result; i != result_end; ++i)
      cout << i->name_ << " (" << i->rating_ << ", " << i->price_ << ")" << endl;
}

Проверялся под MinGW GCC 7.1 с ключами -std=c++03, -pedantic, -Wall.

Код для C++14:

#include <algorithm>
#include <array>
#include <iostream>
#include <string>
#include <vector>
#include <tuple>

using namespace std;

struct place {
   string name_;
   float price_;
   int rating_;
};

bool compare_by_rating_and_name(const place & a, const place & b) {
   const auto t = [](const auto & p) { return tie(p.rating_, p.name_); };
   return t(a) < t(b);
}

template<class Source, class Out_It, class P>
Out_It copy_n_if(size_t n, const Source & src, Out_It to, P predicate)
{
   for(auto b = begin(src), e = end(src); n && b != e; ++b)
      if(predicate(*b)) { *to = *b; ++to; --n; }

   return to;
}

vector<place> fill_places() {
   return {{"Moscow"15003}, {"St. Petersburg"13005}, {"Minsk"5004},
      {"Tokyo"35004}, {"Sydney"50003}, {"Paris"30005}};
}

int main() {
   const auto places = fill_places();

   array<place, 10> result;
   auto result_end = copy_n_if(
         result.size(),
         places,
         begin(result),
         [](const auto & p){ return p.price_ < 4000; });
   sort(begin(result), result_end, compare_by_rating_and_name);

   for(auto i = begin(result); i != result_end; ++i)
      cout << i->name_ << " (" << i->rating_ << ", " << i->price_ << ")" << endl;
}

Проверялся под MinGW GCC 7.1 с ключами -std=c++14, -pedantic, -Wall.

Комментариев нет: