2015-10-14 2 views
4

Как бы мне перевести блок кода в функцию на C++. В C# я могу сделать что-то вроде этого:Передача кода в качестве аргумента (C++)

void Example(Action action) 
{ 
    action(); 
} 

Example(() => { 
    //do something 
}); 

Вся помощь и советы приветствуются.

+6

google 'std :: function' и' C++ lambda' –

+1

Указатели функций очень удобны ... – owacoder

+1

Функциональные объекты тоже полезны. Поиск в Интернете для 'operator()'. –

ответ

4

Вот простой пример, чтобы начать с ...

void Example(void (*x)(void)) 
{ 
    x(); 
} 

и вызов будет ...

Example([] { cout << "do something\n"; }); 

Это очень похоже на ваш C# пример. И есть лучшие, более универсальные способы сделать это, как показывают комментарии. Если бы вы хотели, чтобы вернуть значение и принимать параметр, который вы могли бы сделать что-то вроде этого ...

int Example2(int (*y)(int i), int p) 
{ 
    return y(p); 
} 
// ... 
auto ret = Example2([](int p) -> int { cout << p << "\n"; return p; }, 2); 

Это было бы похоже на C# версии следующим

int Example2(Func<int,int> y, int p) 
{ 
    return y(p); 
} 
// ... 
var ret = Example2((p) => { /*etc*/ return p; }, 2); 
+4

Признание указателя функции крайне ограничено, это означает, что вы можете просто передать только не- захват lambdas или простых указателей функций (=> вызов метода не связанный, просто для примера). Вместо этого вы должны принять 'std :: function'. –

1

Использование std::function<void()> вместо Action и C++ синтаксис для функций лямбды:

void Example(std::function<void()> action) 
{ 
    action(); 
} 

Example([]() { 
    //do something 
}); 

std::function, по сравнению с @ решением Леси с указателями на функции, позволяет передавать lambdas, которые захватывают контекст и вообще любой другой вид вызываемых объектов.

3

C++ 11 эквивалент будет:

void Example(const std::function<void()>& action) 
{ 
    // always good to make sure that action has a valid target 
    if(action != nullptr) 
     action(); 
} 

Example([] { 
    //do something 
}); 
3

std::function<Result(Param1, Param2, ...)> приличная по умолчанию, но у вас есть несколько вариантов:

  1. Объявите вспомогательную функцию и передавать указатель на него. Это было единственное, что можно было сделать на C, и обычный способ сделать это на C++ 98.

    void example(void (*action)()) { 
        action(); 
    } 
    
    void example_action() { 
        std::cout << "action\n"; 
    } 
    
    example(example_action); 
    
  2. Принять указатель на функцию и передать лямбда, что не улавливает не переменных. Lambdas доступны на C++ 11 и более поздних версиях.

    void example(void (*action)()) { 
        action(); 
    } 
    
    example([]() { 
        std::cout << "action\n"; 
    }); 
    
  3. Принимать вызываемый параметр типа шаблона (один с operator() определен), и передать лямбда, которые могут захватывать переменные, или любой другой вызываемый объект («функтор»).

    template<class F> 
    void example(F action) { 
        action(); 
    } 
    
    int x = 4; 
    example([x]() { 
        std::cout << "action (" << x << ")\n"; 
    }); 
    
    struct example_action { 
        void operator()() { 
         std::cout << "action\n"; 
        } 
    }; 
    
    example(example_action()); 
    
  4. std::function Принять объект и передать лямбда, которые могут захватить переменные.

    void example(std::function<void()> action) { 
        action(); 
    } 
    
    int x = 4; 
    example([x]() { 
        std::cout << "action (" << x << ")\n"; 
    }); 
    
  5. Объявите вспомогательную функцию и возьмите указатель на нее во время компиляции.

    template<void (*action)()> 
    void example() { 
        action(); 
    } 
    
    example<example_action>(); 
    

Как любой шаблон, # 3 будет генерировать специализацию example для каждого типа действия, с которыми вы называете его, так что он может увеличить размер бинарного кода, но это не имеет накладных расходов во время выполнения.# 4 будет выделять пространство для закрытия во время выполнения, но будет генерировать только одно определение example в двоичном формате. # 5 реже, но он позволяет функции ввода-вывода использовать оптимизацию, такую ​​как inlining.

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