LINUX.ORG.RU

продемонстрируйте пожалуйста мощь шаблонов и STL


0

0

есть std::vector< std::pair <std::string, double> > vec;

нужно отсортировать его по числу (double). то есть написать:

std::sort( vec.begin(), vec.end(), XXX );

вот на место XXX нужно поставить компаратор. Написать отдельный тип для этого я и сам смогу, но хотелось бы обойтись без объявлений типов, а просто на место XXX забабахать какое-нибудь хитрое выражение ala bind1st. Можно такое сделать?

★★★★★

Можно, но пишется это выражение долго, мучительно и через жопу («написать отдельный тип» как правило гораздо проще). Проще всего это делается через библиотеки шаблонов, поддерживающие лямбда-подобные конструкции (по-моему boost::lambda, и ещё что-то из буста позволяло это делать). И в случае если где-нибудь допустишь ошибку (а это весьма вероятно, т. к. конструкция получается громоздкая и плохочитаемая), то придётся внимательно изучать вывод компилятора размером с несколько экранов.

В общем, весьма унылое это занятие - писать в функциональном стиле на c++. Не надо так делать. Не предназначен он для этого.

slav ★★
()

если есть желание, то можно уже пользоваться лямбдами - в gcc 4.4 и msvc 2010 они поддерживаются

lester ★★★★
()
Ответ на: комментарий от lester

и где там решение? они пишут отдельную функцию для этого. я не хочу тратить строки на мусор. Я хочу скомпоновать std::greater и т.п. в одно выражение, которое поставить на место XXX.

dilmah ★★★★★
() автор топика
Ответ на: комментарий от dilmah

я уже написал - если очень хочется, то пользуйтесь лямбдами

lester ★★★★
()
Ответ на: комментарий от dilmah

Я хочу скомпоновать std::greater и т.п. в одно выражение, которое поставить на место XXX.

А почему не сделать локальный класс?

void SomeClass::someMethod() {
  struct Cmp : public std::binary_function <...> {
    int operator()(double arg1,double arg2) {
       ....
    }
  }
}

Absurd ★★★
()
Ответ на: комментарий от Absurd

ну это уже получше. Меня именно это и волновало — оторванность сущности (компаратора) от того единственного места для которого эта сущность нужна.

dilmah ★★★★★
() автор топика

Давайте не будем усложнять прекрасный и лаконичный C++. Вот мое решение задачи:

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

typedef std::pair<std::string, double> pair_type;

bool LessFuncForPairType(pair_type const& v1, pair_type const& v2)
{
return v1.second < v2.second;
}

void FillVector(std::vector<pair_type>& v)
{
pair_type p;
p.first = "second";
p.second = 5.25;
v.push_back(p);
p.first = "last";
p.second = 31.57;
v.push_back(p);
p.first = "first";
p.second = 0.15;
v.push_back(p);
p.first = "third";
p.second = 14.11;
v.push_back(p);
}

void ShowVector(std::vector<pair_type> const& v)
{
std::cout << "vector contents: " << std::endl;
std::vector<pair_type>::const_iterator ender = v.end();
std::vector<pair_type>::const_iterator i;
for (i = v.begin(); i != ender; i++)
std::cout << i->first << ", " << i->second << std::endl;
}

int main()
{
std::vector<pair_type> vec;

FillVector(vec);
ShowVector(vec);

std::sort(vec.begin(), vec.end(), LessFuncForPairType);

ShowVector(vec);

return 0;
}



---------------
Буду рад ответить на любые ваши вопросы
codebaker...gmail...com

anonymous
()
Ответ на: комментарий от anonymous

Пока делал кросспост в песочницу Хабра, придумал, как улучшить компаратор:

template <typename T1, typename T2>
bool ComparePairBySecondElement(std::pair<T1,T2> const& v1, std::pair<T1,T2> const& v2)
{
return v1.second < v2.second;
}

---------------
Буду рад ответить на любые ваши вопросы
codebaker...gmail...com

anonymous
()
Ответ на: комментарий от anonymous

#include <vector>
#include <string>
#include <boost/bind.hpp>
#include <iostream>
#include <algorithm>


typedef std::pair<std::string, double> cont_type;
std::vector< cont_type > vec;



int main()
{
vec.push_back(std::make_pair("bugoga", 10));
vec.push_back(std::make_pair("loh", 20));
vec.push_back(std::make_pair("hren", 15));

std::sort(vec.begin(), vec.end(), boost::bind(std::less<double>(), boost::bind(&cont_type::second, _1), boost::bind(&cont_type::second, _2)));

std::cout << vec[0].first << ", " << vec[0].second << std::endl;
std::cout << vec[1].first << ", " << vec[1].second << std::endl;
std::cout << vec[2].first << ", " << vec[2].second << std::endl;
return 0;
}

P1XeL
()
Ответ на: комментарий от P1XeL

std::sort(vec.begin(), vec.end(), boost::bind(std::less<double>(), boost::bind(&cont_type::second, _1), boost::bind(&cont_type::second, _2)));

По до мной только что образовался тепленький, дымящийся кирпич.

baverman ★★★
()
Ответ на: комментарий от baverman

Если ты не понимаешь шаблонов, то это твои проблемы, шаблоны давно уже вошли в практику программирования на плюсах. man александреску

P1XeL
()
Ответ на: комментарий от baverman

Еще раз повторяю, если не умеешь пользоваться шаблонами. то это твои проблемы.

Почитай для чего и как создавался stl.

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


template <typename Type> void my_sort(std::vector<Type> &vec)
{
std::sort(vec.begin(), vec.end(), std::less<Type>());
}

std::vector<int> t;

int main()
{
t.push_back(10);
t.push_back(30);
t.push_back(20);
t.push_back(15);

my_sort(t);

std::cout << t[0] << std::endl;
std::cout << t[1] << std::endl;
std::cout << t[2] << std::endl;
std::cout << t[3] << std::endl;
}

P1XeL
()
Ответ на: комментарий от baverman

> Если шаблоны так прекрасны, почему нельзя написать

std::sort(vec)

Потому что стандартный operator< для std::pair сравнивает по первому элементу пары.

bvvv
()
Ответ на: комментарий от P1XeL

Какой чудесный лаконичный кусок крестятины! Лисп по сравнению с сиим кодом, которым, право, мог бы гордиться Александреску, выглядит унылыми булшитом:

(map nil (lambda (x) (format t "~a, ~a~%" (car x) (cdr x)))
     (sort '(("bugoga" . 10) ("lol" . 20) ("hren" . 15)) #'< :key #'cdr))

mv ★★★★★
()

А почему просто не перегрузить оператор '<' в простейшем производном классе? Наверняка в библиотеке он объявлен как virtual.

Кроме того, есть еще более простое решение: обернуть в класс, с обратным порядком аргументов в паре, после чего использовать все стандартное.

annoynimous ★★★★★
()
Ответ на: комментарий от annoynimous

Более, того, класс надо сделать ссылочным (кажется, это называется «интерфейсный указатель») и тогда никакого излишних накладных расходов, кроме одного косвенного обращения

annoynimous ★★★★★
()

в gcc 4.4 должно как-то так быть:

std::sort(
    vec.begin(),
    vec.end(),
    [bool](
        std::pair <std::string, double> x,
        std::pair <std::string, double> y )
    { return x.second < y.second; } );
lester ★★★★
()
Ответ на: комментарий от lester

Если предусмотрительно сделать typedef и не указывать явно возвращаемый тип, то все смотрится просто и красиво:

std::sort( vec.begin(), vec.end(), []( myT x, myT y ) { return x.second < y.second; } );

lester ★★★★
()
Ответ на: комментарий от mv

> Лисп выглядит унылыми булшитом:
> (map nil (lambda (x) (format t "~a, ~a~%" (car x) (cdr x))) (sort '(("bugoga" . 10) ("lol" . 20) ("hren" . 15)) #'< :key #'cdr))


однозначно

lester ★★★★
()
Ответ на: комментарий от lester

> Если предусмотрительно сделать typedef и не указывать явно возвращаемый тип, то все смотрится просто и красиво: std::sort( vec.begin(), vec.end(), []( myT x, myT y ) { return x.second < y.second; } );

Если натянуться задом на кактус и при этом улыбаться, то никто не узнает, как вам на самом деле больно.

mv ★★★★★
()
Ответ на: комментарий от mv

> Если натянуться задом на кактус и при этом улыбаться, то никто не узнает, как вам на самом деле больно.

так вот что чувствуют лисперы..., сочувствую

lester ★★★★
()
Ответ на: комментарий от lester

> так вот что чувствуют лисперы..., сочувствую

У лисперов боль в заднице бывает (идеального ЯП не существует), но к тому моменту крестофилы уже давно жопным взрывом разбросаны кусками по округе.

mv ★★★★★
()
Ответ на: комментарий от lester

> долгое общение с лиспом отложило отпечаток на ваши ассоциации

У меня хоть фантазия есть, в отличие от участников комитета по стандартизации C++. Эти кексы даже PITA не в том месте делают.

mv ★★★★★
()
Ответ на: комментарий от lester

Меня это устраивает, если кроме этого больше ничего городить не надо. По семантике оно не на много от лиспа отличается. Ну, разве что, тут бы ещё foreach пригодился, но он в boost'е есть. Ты же сам ведь не будешь спорить, что таки лямбды в частности и в функциональный подход, употреблённый в тему, код укорачивают и упрощают для понимания?

mv ★★★★★
()
Ответ на: комментарий от mv

> Ну, разве что, тут бы ещё foreach пригодился

опять же с выводом типов он делается одним макросом

> Ты же сам ведь не будешь спорить, что таки лямбды в частности и в функциональный подход, употреблённый в тему, код укорачивают и упрощают для понимания?


нет

lester ★★★★
()
Ответ на: комментарий от lester

> доо

Увидев 2 строки на лиспе вместо 20 на плюсах не задуматься может только человек без фантазии. Для обычного, усреднённого программирования, т.е. процентов 90% от всех задач, Лисп лучше.

mv ★★★★★
()
Ответ на: комментарий от P1XeL

> Еще раз повторяю, если не умеешь пользоваться шаблонами. то это твои проблемы.

А твоя проблема в том, что ты непонятно зачем пишешь какие-то мутные примеры. Готовишься к выступлению в чемпионате по Boost?

tailgunner ★★★★★
()
Ответ на: комментарий от mv

> Увидев 2 строки на лиспе вместо 20 на плюсах не задуматься может только человек без фантазии

хочешь я тебе на С++ все напишу короче чем предложили выше и тоже влеплю все в две строки?

lester ★★★★
()
Ответ на: комментарий от lester

> хочешь я тебе на С++ все напишу короче чем предложили выше и тоже влеплю все в две строки?

Давай в одну, чего уж там...

mv ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.