2014-01-30 4 views
5

у меня есть следующий код:Как вызвать функцию несколько раз в C++ с различными параметрами

object a,b,c; 
fun (a); 
fun (b); 
fun (c); 

Интересно, если есть ли способ сделать что-то подобное в C++ 98 или C++ 11 чтобы:

call_fun_with (fun, a, b, c); 

Благодарности

+3

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

+3

Введите ['std :: vector'] (http://en.cppreference.com/w/cpp/container/vector) и используйте [' std :: for_each'] (http://en.cppreference.com/ж/CPP/алгоритм/for_each)? –

+0

Это вариант, но мне интересно, есть ли какая-то особенность на C++ для работы с этим –

ответ

6

Вы можете использовать следующие с помощью VARIADIC шаблона:

template <typename F, typename...Ts> 
void fun(F f, Ts&&...args) 
{ 
    int dummy[] = {0, (f(std::forward<Ts>(args)), 0)...}; 
    static_cast<void>(dummy); // remove warning for unused variable 
} 

или в C++ 17, с откидным выражением:

template <typename F, typename...Ts> 
void fun(F&& f, Ts&&...args) 
{ 
    (static_cast<void>(f(std::forward<Ts>(args))), ...); 
} 

Теперь, проверить:

void foo(int value) { std::cout << value << " "; } 

int main(int argc, char *argv[]) 
{ 
    fun(foo, 42, 53, 65); 

    return 0; 
} 
+0

Очень элегантное решение! –

+0

Приятная часть заключается в том, что это даже работает, когда 'foo' перегружен и/или cnversions не заданы:' void foo (int); void foo (std :: string); fun (foo, 42, «abc», 3.5); '- будет вызывать' foo (std :: string ("abc")) ' – MSalters

+0

@ Jarod42 Вы должны прочитать комментарии на этой странице, приведение void не переносится способ отключить предупреждение http://herbsutter.com/2009/10/18/mailbag-shutting-up-compiler-warnings/ – galop1n

5

Использование C++ 11, вы можете использовать std::function, таким образом (что довольно быстро написать ИМО)

void call_fun_with(std::function<void(int)> fun, std::vector<int>& args){ 
    for(int& arg : args){ 
     fun(arg); 
    } 
} 

или немного более общий характер:

template<typename FTYPE> 
void call_fun_with(FTYPE fun, std::vector<int>& args){ 
    for(int& arg : args){ 
     fun(arg); 
    } 
} 

Live example

Live example, templated version

Примечание: std::function аргументы шаблона должны быть определены следующим образом: return_type(arg1_type, arg2_type,etc.)

EDIT: A lternative может использовать std::for_each, что фактически делает практически то же самое, но мне не очень нравится семантика, которая больше похожа на «для всего, что в этом контейнере, сделайте ...». Но это только я и мой (возможно, глупый) способ кодирования :)

+0

Thats отличное решение, Спасибо за ответ! : D –

+0

Почему вы используете функцию 'std :: function' вместо использования параметра шаблона? Даже если у вас нет вариативных шаблонов, принятие типа функции в качестве параметра шаблона упрощает работу. – MSalters

+0

@MSalters Хорошо, потому что, честно говоря, я действительно не чувствую себя комфортно с этим. Конечно, [** это работает **] (http://coliru.stacked-crooked.com/a/78437ec85803934d), хотя я не уверен, что это был бы правильный способ сделать это с помощью параметра шаблона. – JBL

7

Здесь предлагается вариационное решение шаблона.

#include <iostream> 

template < typename f_> 
void fun(f_&& f) {} 

template < typename f_, typename head_, typename... args_> 
void fun(f_ f, head_&& head, args_&&... args) { 
    f(std::forward<head_>(head)); 
    fun(std::forward<f_>(f), std::forward<args_>(args)...); 
} 

void foo(int v) { 
    std::cout << v << " "; 
} 

int main() { 
    int a{1}, b{2}, c{3}; 
    fun(foo, a, b, c); 
} 
+1

Я бы поднял вас (поскольку ваше решение не наносит лишних издержек), но вы используете незаконные идентификаторы. Все, что содержит двойное подчеркивание, зарезервировано для компилятора и стандартной библиотеки. – Angew

+0

вот что я точно искал, огромное спасибо! –

+0

@Angew был уверен, что он был только в начале идентификатора, исправлен. – galop1n

1

Есть много разных способов в ...

#include <iostream> 
#include <vector> 
#include <algorithm> 

void foo(int x) { 
    std::cout << x << "\n"; 
} 

void call_fun_with(std::function<void(int)> fn, std::vector<int> lst) { 
    for(auto it : lst) 
     fn(it); 
} 

int main() { 
    std::vector<int> val = {1,2,3,4,5}; 

    // c++98 
    std::for_each(val.begin(), val.end(), foo); 

    // c++11 
    // vector 
    call_fun_with(foo, val); 

    // c++11 
    // initializer_list 
    int a=0, b=1, c=2; 
    call_fun_with(foo, {a,b,c}); 
} 

см here.

+0

Этот ответ может быть самым полным. Благодаря!! –

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