Самые полезные или удивительные короткие лайнеры STL
Я ищу практические и образовательные образцы кода С++/STL в нескольких строках. Мои фактические фавориты:
-
Пусто вектор, освобождающий его зарезервированную память:
vector <...>().swap (v)
(своп с временным)
-
Скопируйте карту в вектор:
map<T1, T2> myMap;
vector< pair<T1, T2> > myVec(myMap.begin(), myMap.end());
// or
myVec.assign(myMap.begin(), myMap.end());
-
Пользовательский, невосстанавливаемый раскол:
vector<string> &mysplit(const string &s, char delim, vector<string> &elems) {
stringstream ss(s);
string item;
while(getline(ss, item, delim)) { elems.push_back(item); }
return elems;
}
Ответы
Ответ 1
// std::back_inserter usage ( std::inserter for map )
std::copy( source.begin(), source.end(), std::back_inserter( container ) );
-
// mem_fun and bind usage (but boost better)
std::some_algorithm(..., std::mem_fun( func ) );
не очень полезный, но мощный:
проверка сортируется в контейнере
std::adjacent_find( container.begin(), container.end(), greater<Container::value_type>() ) == container.end()
также примеры, упомянутые вами и dirkgently.
Ответ 2
Мое избранное - копирование контейнеров на выход:
И копирование входного потока в контейнер.
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>
int main()
{
std::vector<int> data;
std::copy(std::istream_iterator<int>(std::cin),
std::istream_iterator<int>(),
std::back_inserter(data)
);
std::copy(data.begin(),data.end(),
std::ostream_iterator<int>(std::cout,"\n")
);
}
Ответ 3
Для удаления элементов, удаленных с помощью remove()
или remove_if()
, требуется следующая идиома:
vector<int> v;
...
v.erase(remove(v.begin(), v.end(), 42), v.end());
remove()
и remove_if()
просто перемещают не удаленные элементы вперед и сообщают, где заканчивается новый диапазон - они не (и не могут) их удалять, потому что они могут работать на любом произвольном диапазоне итераторов, а не только контейнер.
Ответ 4
copy(istreambuf_iterator<char>(cin), istreambuf_iterator<char>(),
ostream_iterator<char>(cout));
Другая используемая идиома - инициализация контейнера из массива:
#include <map>
using namespace std;
int main() {
typedef std::map<char,int> LUT;
typedef LUT::value_type LUT_item_t;
const LUT_item_t items[] = { LUT_item_t('b',1),
LUT_item_t('a',5)
};
LUT my_map(items, items + sizeof items/sizeof items[0]);
return 0;
}
Но если вы хотите чистую магию, посмотрите Boost Lambda Library;) Пример:
vector<int*> vp(10);
sort(vp.begin(), vp.end(), *_1 > *_2);
Ответ 5
Мне больше всего нравится использовать bind1st/bind2nd/mem_fun в виде делегатов.
// will call a->func(v[i])
for_each(v.begin(), v.end(), bind1st(mem_fun(&A::func), &a));
// will call w[i]->func(72)
for_each(w.begin(), w.end(), bind2nd(mem_fun(&A::func), 72));
Использование boost bind и функции намного лучше, но впечатляет, что можно сделать только с помощью STL.
Ответ 6
Для вашего второго примера используйте тип значения:
#
Copy a map to a vector:
typedef map<T1, T2> MyMap;
MyMap myMap;
vector< MyMap::value_type > myVec(myMap.begin(), myMap.end());
Ответ 7
Мне нравится этот цикл для каждой строки в файле. Из колонки Эндрю Кенига в докторе Доббсе.
for (string s; getline(stream,s); ) {
// Process line
}
Ответ 8
Использование std:: for_each в сочетании с лямбда-функцией (начиная с С++ 11)
std::vector<int> v(20);
std::for_each( v.begin(), v.end(), [] (int item)
{
std::cout << item;
} );
вместо
for(std::vector<int>::const_iterator it = v.begin(); it != v.end(); ++it)
{
std::cout << *it;
}
делает для более перспективных циклов.