Возможно ли иметь функцию (-name) в качестве параметра шаблона в C ++? - PullRequest
14 голосов
/ 25 октября 2010

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

void f(int x);
void g(int x);

...

template<typename F>
void do_work()
{
  int v = calculate();
  F(v);
}

...

do_work<f>();
do_work<g>();

Возможно ли это?


Чтобы устранить возможную путаницу: под «параметром шаблона» я подразумеваю параметр / аргумент для шаблона и , а не параметр функции, тип которой является шаблонным .

Ответы [ 4 ]

22 голосов
/ 25 октября 2010

Ваша идея в порядке, но вы передаете не тип, а значение (в частности, указатель на функцию>. В качестве альтернативы, передайте шаблонную политику, предоставляющую функции - это хорошая идея, чтобы прочитать Modern C ++ Design от Andrei Alexandrescu.

#include <iostream>

int f(int x) { return 2 * x; }
int g(int x) { return -3 * x; }

typedef int (*F)(int);

template<F f> 
int do_work() 
{ 
    return f(7);
} 

int main()
{
    std::cout << do_work<f>() << '\n'
              << do_work<g>() << '\n'; 
}

OR

int calculate() { return 4; }

struct F { int do_something_with(int x) { return 2 * x; } };
struct G { int do_something_with(int x) { return -3 * x; } };
// or, make these functions static and use Operator::do_something_with() below...

template<typename Operation> 
int do_work() 
{ 
    int v = calculate(7);
    return Operation().do_something_with(v);
} 

int main()
{
    std::cout << do_work<F>() << '\n'
              << do_work<G>() << '\n'; 
}
9 голосов
/ 25 октября 2010

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

struct F { static void func(int x) { /*whatever*/ } };
struct G { static void func(int x) { /*whatever*/ } };

template<class T>
void do_work() {
    T::func(calculate());
}

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

9 голосов
/ 25 октября 2010

Вы можете иметь указатели на функции в качестве параметров шаблона, но функциональные объекты более "C ++ ish". Однако вы можете написать свой шаблон функции так, чтобы он принимал оба варианта:

#include <iostream>

void f(int x)
{
    std::cout << "inside function f\n";
}

struct g
{
    void operator()(int x)
    {
        std::cout << "inside function object g\n";
    }
};

template <typename Functor>
void do_work(Functor fun)
{
    fun(42);
}

int main()
{
    // template argument is automatically deduced
    do_work(&f);
    // but we could also specify it explicitly
    do_work<void(*)(int)>(&f);

    // template argument is automatically deduced
    do_work(g());
    // but we could also specify it explicitly
    do_work<g>(g());
}

Здесь имя Functor намекает на любой тип, который можно вызвать с помощью синтаксиса f(x). Функции поддерживают этот синтаксис естественным образом, а в случае объектов функций f(x) является синтаксическим сахаром для f.operator()(x).

6 голосов
/ 25 октября 2010

Нет, вам нужно заключить функции в класс-оболочку с помощью operator().Вот пример:

class Functor_f
{
public:
    void operator()(int x)
    {
    }
};

class Functor_g
{
    public:
    void operator()(int x)
    {
    }
};



template<typename F>
void do_work()
{
  F f;
 int v = calculate();
  f(v);
}


int main()
{
    do_work<Functor_f>();
    do_work<Functor_g>();

}

Вы можете использовать std::ptr_fun, чтобы сделать это автоматически для вас.Например:

void f(int x)
{
}

void g(int x)
{
}

template<typename F>
void do_work(F f)
{
 int v = calculate();
  f(v);
}


int main()
{
    do_work(std::ptr_fun(f));
    do_work(std::ptr_fun(g));

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...