2009-10-18 4 views
1

Просмотрев преимущества метапрограммирования в Ruby и Python, но будучи связанными с языками более низкого уровня, такими как C++ и C для реальной работы, я думаю о манерах, с помощью которых можно объединить два , Один экземпляр входит в простую задачу для сортировки списков произвольных структур/классов. Например:Custom C++ Preprocessor/Typeful Macros

struct s{ 
    int a; 
    int b; 
}; 

vector<s> vec; 
for(int x=0;x<10;x++){ 
    s inst; 
    inst.a = x; 
    inst.b = x+10; 
    vec.push_back(inst); 
} 

В конце концов, я хотел бы, чтобы иметь возможность сортировать инст произвольно с минимальным количеством шаблонного кода. Самый простой способ, я могу видеть, чтобы сделать это, чтобы использовать то STL в:

sort(vec.begin(),vec.end()); 

Но это требует от меня, чтобы написать метод, который может сравнить «STRUCT S» с. Я бы предпочел:

sort(vec,a ASC,b DESC); 

Это очень ясно не действительный C++.

Каков наилучший способ осуществить мою мечту? Если бы у меня был какой-то типный макрос, это показало бы мне, каков тип элементов вектора, тогда было бы тривиально писать макросы препроцессора , чтобы создать функцию, необходимую для сортировки.

Альтернативой, похоже, является создание собственного препроцессора. Это работает хорошо, вплоть до момента, когда я должен снова вывести тип «vec». Есть простой способ сделать это?

Контекст: Меньше кода = меньше ошибок, соревнований по программированию.

ответ

2

Для выше, вы можете использовать Boost.Lambda, чтобы написать функцию сравнения инлайн, так же, как лямбда Python:

using namespace boost::lambda; 

std::sort(vec.begin(), vec.end(), (_1 ->* &s::a) < (_2 ->* &s::a)); 

Это, конечно, предполагает, что вы сортировкой а.

Если выражения, которые вы ищете, намного сложнее, вам лучше написать отдельную функцию; даже в таких языках, как Python и Ruby с встроенной поддержкой закрытий, сложные закрытия становятся совершенно нечитаемыми в любом случае.

Предупреждение: Указанный код не проверен.

Надеюсь, это поможет!

+0

Блестяще, я знал, что кто-то должен был сделать это с помощью шаблонов. Благодаря! –

-2

Для C++ стандартная библиотека предлагает заголовок algorithms, который содержит много полезных функций, которые работают с различными контейнерами. Пример для ваших целей будет:

bool sCompare(const s & s1, const s & s2) { 
return s1.a+s1.b/1000 < s2/a+s2.b/1000; 
} 

vector<s> vec; 
... 
std::sort(vec.begin(), vec.end(), sCompare); 

рода имеет прототип, который выглядит примерно так:

template<class Iter, class Op> 
void sort(Iter& start, Iter& stop, Op& op); 

Большинство из этих алгоритмов должно работать на любой из стандартных контейнеров (некоторые из них специфичны для отсортированных контейнеров , некоторые ассоциативные и т. д.). Я считаю, что сортировка (и другие) даже будет работать с массивами (Итераторы, основа алгоритмов, построены так, чтобы как можно ближе эмулировать указатели на элементы массива).

Короче говоря, используя современный C++, вам не понадобится специальный препроцессор для достижения того, что вы пытаетесь сделать.

BTW, если вы заявили, что используете std или std :: sort, тогда sort(vec.begin(),vec.end())is действительный C++;

+0

Здесь явно указано неверно –

2

Я бы записал оператор сравнения для struct. Бонус, связанный с определением оператора сравнения, заключается в том, что вы не получаете множественных сравнений лямбда, разбросанных по всему месту. Скорее всего, вам понадобится оператор сравнения больше, чем один раз, так почему бы не определить его один раз в логическом месте (вместе с типом)?

Лично я предпочитаю писать код один раз и держать его в определенном месте, которое особенно легко найти. Я также предпочитаю писать код, который является идиоматическим по отношению к языку, на котором я пишу. В C++ я ожидаю конструкторы, деструкторы, меньше, чем операторы, и тому подобное. Вам лучше писать меньше, чем оператор, а затем позволить std::sort(vec.begin(), vec.end()) выполнить свою работу. Если вы действительно хотите, чтобы сделать код ясно, то сделать что-то вроде:

struct S { 
    int a, b; 
    bool less_than(S const& other) {...}; 
}; 
bool operator<(S const& left, S const& right) { 
    return left.less_than(right); 
} 

Если определить функцию-член, чтобы сделать сравнение, а затем предоставить оператору в пространстве имен уровня, жизнь намного легче, когда у вас есть чтобы отрицать сравнение. Например:

void foo(std::vector<S>& svec) { 
    std::sort(svec.begin(), svec.end(), std::not1(&S::less_than)); 
} 

Этот код не проверен, но вы получаете эту идею.

0

Если вы используете C++ 11, вы можете использовать Linq сортировать так:

auto q = LINQ(from(x, vec) orderby(ascending x.a, descending x.b)); 

Или, если вам не нравится синтаксис запросов, вы можете использовать методы расширения, а также:

auto q = vec | linq::order_by([](s x) { return x.a; }) 
      | linq::then_by_descending([](s x) { return x.b; }); 

Оба функционально эквивалентны.