2016-12-31 1 views
2

я в настоящее время код следующего вида:C++ Повторные делать-если-делать шаблон

Do1(A); 
if (B != null) Do1(B); 

Do2(A, true); 
if (B != null) Do2(B, true); 

Do3(A); 
if (B != null) Do3(B); 

Так несколько раз, я исполняю что-то для объекта А, и если указан B, я делаю это для B Это означает, что весь мой код дублируется, и я хотел бы изменить его, но я не могу придумать хороший способ улучшить этот шаблон.

Единственная идея, которую я имел до сих пор что-то вроде

auto doBoth = [&A,&B](function<void(const T&)> f) { 
    f(A); 
    if (B != null) f(B); 
}; 

doBoth(&Do1); 
auto do2_bind = [](const T& obj) {Do2(obj, true);}; 
doBoth(do2_bind); 
doBoth(&Do3); 

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

Редактировать: Из ответов и комментариев я вижу, что должен был внести некоторые разъяснения. Прошу прощения за путаницу.

  1. А и В одного и того же типа и имеют что-то вроде Foo * или опционального < Foo>, которая позволяет тест на нуль

  2. я могу использовать только C++ 11 особенности

  3. Кодовые блоки (которые я сокращенно как DoN здесь) могут быть более сложными, чем просто один вызов функции. Например, если бы:

    Do1(A); 
    Do2(A); 
    if (B != null) { 
        Do1(B); 
        Do2(B); 
    } 
    

где порядок операций важен.

+0

C++ 17 lambdas с параметрами автоматической настройки должны сделать это намного приятнее. –

+1

@BenVoigt: Это функция C++ 14. –

+0

Не могли бы вы сделать это? 'template void DoAll (X x) { Do1 (x); Do2 (x, true); Do3 (x); } /* ... */ DoAll (a) if (b) DoAll (b); ' Или вызовы b зависят от побочных эффектов от вызовов? – WaltK

ответ

5

Ваш подход разумный, но вам действительно не нужен std::function. Просто шаблон, который принимает вызываемый:

template<typename A, typename B, typename Func> 
void do_for_both(A&& a, B&& b, Func&& func) 
{ 
    func(std::forward<A>(a)); 
    if(b != nullptr) 
    func(std::forward<B>(b)); 
} 

выше будет принимать как сырые указатели и optional S, которые держат указатель. Ваши звонки будут потом просто стать:

do_for_both(a, b, [](auto&& param){ 
    Do1(param); 
}); 

do_for_both(a, b, [](auto&& param){ 
    Do2(param, true); 
}); 

Ну, выше будет работать на C++ 14. Но теперь я заметил требование C++ 11. Таким образом, этот ответ теперь является просто ссылкой.

+2

Согласен. (Хотя заменить «правильно» «разумным», возможно, - нет абсолютов в том, что мы делаем!) –

+0

Как именно это работает? 'Do1' - две функции: у него есть перегрузка для' A' и 'B'. Как вы передаете две функции как одну? Вы должны получить ошибку компиляции. –

+1

@NicolBolas: Не в соответствии с кодом в вопросе - как 'a', так и' b' являются типом 'T', совместимым с передачей в' std :: function ' –