2014-02-14 3 views
1

Я читал сообщения/статьи о lambdas, указатели функций, анонимные функции вообще и другие связанные вещи, но ничего, что я видел (я думаю), не ударил точно что я хочу делать.Передача анонимной функции как только параметра другой функции (C++)

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

Предполагая, что эта функция, которая принимает мою анонимную функцию в качестве аргумента, находится в main.cpp, поэтому она вызвана из main, можно ли реализовать это простым способом?

В основном я пытаюсь выяснить синтаксис в C++ для выхода из этого:

// Some function with partially duplicated code 
void OriginalA() 
{ 
    DoThingsA(); 

    // unique code 

    DoThingsB(); 
} 

// Another function with partially duplicated code 
void OriginalB() 
{ 
    DoThingsA(); 

    // unique code 

    DoThingsB(); 
} 

Для этого:

// Encapsulate shared functionality 
// <param name="action">User defined action</param> 
void UniqueWrapper(Action action) 
{ 
    DoThingsA(); 

    action(); 

    DoThingsB(); 
} 

// New implmentation of A 
void NewA() 
{ 
    UniqueWrapper(() => 
    { 
     // unique code 
    }); 
} 

// New implementation of B 
void NewB() 
{ 
    UniqueWrapper(() => 
    { 
     // unique code 
    }); 
} 

Который я нашел, как # 1 здесь: http://www.wildbunny.co.uk/blog/2012/11/01/10-steps-to-becoming-a-better-programmer/

Но установка, подобная этой, где буквально все, что вам нужно будет сделать для вызова, является:

theFunctionName(() => { /*unique things to do*/ }); 

Если этот ^^ является синтаксисом легального вызова, то я просто не уверен, как этот параметр выглядит в определении FunctionName, очевидно, что это не действие (действие), как в приведенном выше примере.

ответ

1

Есть несколько способов сделать это, но не все будут работать на всех платформах (например, потому что они требуют C++ 11 функций (лямбды).

Более классический подход будет что-то вроде этого (без анонимной функции):

#include <iostream> 

typedef void(*Action)(); 

void UniqueWrapper(Action action) { 
    std::cout << "Generic Code 1" << std::endl; 
    action(); 
    std::cout << "Generic Code 2" << std::endl; 
} 

void CustomAction(void) { 
    std::cout << "Custom Code" << std::endl; 
} 

int main(int argc, char **argv) { 
    UniqueWrapper(&CustomAction); 
    return 0; 
} 

конечно, вы могли бы использовать некоторые макро махинации, чтобы сделать это более «динамический»

После того, как вы принимаете C++ 11 кода, а также (что необходимо иметь лямбды. как объяснено), вы можете сделать что-то вроде этого:

#include <iostream> 

typedef void(*Action)(); 

void UniqueWrapper(Action action) { 
    std::cout << "Generic Code 1" << std::endl; 
    action(); 
    std::cout << "Generic Code 2" << std::endl; 
} 

int main(int argc, char **argv) { 
    UniqueWrapper([](){ 
      std::cout << "Custom Code" << std::endl; 
     }); 
    return 0; 
} 

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

+0

Это работает только потому, что вы ничего не захватили в лямбда. Как только вы это сделаете, это ломается тонкими способами. IMO лучший способ принять вызываемый аргумент в C++ - это шаблон (он работает для всего без накладных расходов). 'std :: function' всегда вводит служебные данные, указатель функции предотвращает inlining и не работает для функторов. Это действительно резервные копии, если вы не можете использовать шаблон по любой причине. – pmr

3

Заменить Action аргумент с:

template<typename Function> 
void UniqueWrapper(Function action) { 
    DoThingsA(); 
    action(); // call the passed in function 
    DoThingsB(); 
}; 

Называйте это, как это:

void NewA() { 
    UniqueWrapper([]() {}); 
    //   ^^^^^^^ 
    //  C++11 lambda syntax 
} 

Вместо лямбда вы также можете использовать указатели на функции, функции-члены (с помощью std::mem_fn) или функторы. Каждый вид вызываемого объекта будет работать.

Смежные вопросы