2014-02-18 6 views
3

Я работаю над некоторым кодом, и у меня есть раздел, где я выполняю одну функцию сортировки. Для его реализации я решил, что проще всего перегрузить оператор <. То, что я бы предпочел сделать, это переместить реализацию сортировки ближе к фактическому вызову, используя какой-то boost :: bind, boost :: phoenix, lambda или какой-либо другой тип реализации. К сожалению, у меня нет доступа к новым функциям C++ 11. Ниже приведен пример кода.Как реализовать функцию лямбда для алгоритма сортировки с участием членов объекта, косвенности и литья?

// In a header 
struct foo 
{ 
    char * a; 
    char * c_str() { return a; } 
} 

// In a header 
struct bar 
{ 
    foo * X;   

    bar(foo * _X) : X(_X) {} 
    bool operator < (const bar& rhs) const 
    { 
     return std::string(X->c_str()) < std::string(rhs.X->c_str()); 
    } 
}; 

struct bars : public std::vector<bar> { ... some stuff }; 

// Some other header 
bars Bs; 


// A cpp file 
... other stuff happens that fills the Xs vector with objects 

...::Function() 
{ 
    // Current use and it works fine 
    std::sort(Bs.begin(), Bs.end()) 

    // Would like something that accomplishes this: 
    // std::sort(Bs.begin(), Bs.end(), 
    // std::string(lhs.X->c_str()) < std::string(rhs.X->c_str())) 

    // A non-working example of what I'm trying to do 
    // std::sort(Xs.begin(), Xs.end(), 
    //  std::string((bind(bar::X->c_str(), _1)) < 
    //  std::string((bind(bar::X->c_str(), _2))) 
} 

Я теряюсь, пытаясь выяснить, как получить доступ к указателям членов, функций члена и затем отливал результат все в функции подталкивания :: связывания.

Благодарим за помощь.

ответ

1

Я уверен, что вы можете крутить свой путь из этого, используя широкие порции

  • подталкивания Phoenix bind и lambda
  • подталкивания Bind protect

Однако, я научился избегайте этих ситуаций. Редактировать На самом деле, см. Ниже для одного такого приспособления. Я нахожу эту очень склонную к ошибкам и трудно рассуждать.

То, что вы видите, является, по сути, нарушением Law Of Demeter. Если вы «просто» написали код (не в лямбда), он уже обрабатывал бы слишком много задач.

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

Вторая вещь, которую я хотел бы сделать, это/extract/различные обязанности от вашего компаратора. Обратите внимание, что компаратор делает три вещи:

  • Доступ к c_str() на X в LHS
  • Доступ к c_str() из X в правой части
  • сравнить два

Первые два шага - явные кандидаты на добычу. Напишем общий компаратор, который остается первым:

template <typename F> 
struct compare_by_impl { 
    compare_by_impl(F f = F{}) : _f(std::move(f)) {} 

    template <typename T, typename U> 
    bool operator()(T const& a, U const& b) const { 
     return _f(a) < _f(b); 
    } 
    private: 
    F _f; 
}; 

Как всегда, приятно иметь фабричную функцию, которая будет выводить тип аксессора (в случае, если вы можете уйти только с помощью Phoenix там, это сэкономит вам указав (аркан) typenames участвует в шаблонах выражений):

template <typename Accessor> 
compare_by_impl<Accessor> comparer_by(Accessor&& f) { 
    return compare_by_impl<Accessor>(std::forward<Accessor>(f)); 
} 

Теперь уже можно было переместить реализацию с сортировки по телефону:

void Function() 
{ 
    struct accessX_c_str { 
     std::string operator()(bar const& b) const { 
      return b.X->c_str(); 
     } 
    }; 

    std::sort(Bs.begin(), Bs.end(), comparer_by(accessX_c_str())); 
} 

Я лично оставим его там.

Вот некоторые более скрученных хитрые:

// to avoid `comparer_by` 
std::sort(Bs.begin(), Bs.end(), phx::bind(accessX_c_str(), arg1) < phx::bind(accessX_c_str(), arg2)); 


// to avoid any helper types (!?!?!? untested!) 
std::sort(Bs.begin(), Bs.end(), 
     phx::construct<std::string>(phx::bind(&foo::c_str, phx::lambda [ phx::bind(&bar::X, arg1) ](arg1))) 
     < phx::construct<std::string>(phx::bind(&foo::c_str, phx::lambda [ phx::bind(&bar::X, arg1) ](arg2))) 
    ); 
+0

Хорошо. Просто вспомнил требование C++ 03. Вот ** [все адаптировано к C++ 03] (http: // coliru.stacked-crooked.com/a/36fed5e249b95450)** (обратите внимание на комментарии и протокол 'result_type'). И вот оригинал [C++ 11 для сравнения] (http://coliru.stacked-crooked.com/a/b6d7e77ec7624645) (** ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ ** Я до сих пор не претендую на Phoenix contraption/works /. Он компилируется :)) – sehe

+0

К сожалению, пропущен возврат к 'std :: string': ** [C++ 03 адаптирована версия] (http://coliru.stacked-crooked.com/a/4394162bfd38e6aa) ** , и [C++ 11 тоже] (http://coliru.stacked-crooked.com/a/bec11b3222c3decd) – sehe

+0

Наконец-то у меня появилось некоторое время, чтобы вернуться и на самом деле изучить этот код, и я понимаю, что вы пытаетесь сделать, хотя я действительно чувствую, что это очень сложный код для одного сортировки, а не то, что мерзость звонков с фениксами является отличным решением. C++ 11 делает гораздо более простой один код. Спасибо за хорошо сделанные примеры. – ApockofFork