2010-10-25 71 views
12

我不想函数指针的开销,我只是想为两个不同的功能具有相同签名相同的代码:是否有可能在C++中有一个函数(-name)作为模板参数?

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>(); 

这可能吗?


要清除了可能出现的混淆:用“模板参数”我的意思是参数/参数模板函数参数类型为模板

回答

6

一种方法是极有可能产生直接的函数调用,因为它可以让编译器没有选择,是使用静态成员函数:

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。当然,我保证什么都没有,但是即使禁用了优化,生成的代码也应该是合理的。

+0

+1:非常好的解决方案。不适用于支持我的问题的问题,但作为一般解决方案非常好! – 2010-10-25 19:45:12

9

您可以将指针指向函数作为模板参数,但函数对象更多的是“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()); 
} 

这里,在名称的任何类型的通过f(x)语法调用Functor提示。函数自然支持这个语法,而在函数对象的情况下,f(x)是语法糖f.operator()(x)

+1

+1 ...并且它们被编译为直接调用,在运行时没有函数指针调用开销。 – Doug 2010-10-25 09:50:41

+0

@Doug:没有保证。尽管很可能,例如, 'std :: sort'从这个优化中受益匪浅。 – MSalters 2010-10-25 10:03:31

+0

您的实现将匹配'typename Fun'参数到函数原型'void(*)(int)',然后为这两个调用使用相同的实例 - 不是内联:这就是为什么您最终将函数指针传递为“do_work(趣味趣味)”的运行时参数。 – 2010-10-25 10:10:41

6

不,您需要用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)); 

} 
+0

第一个例子(没有'std :: ptr_fun')给出了更好的实际内联机会 - 并且(尽管当然这取决于很多)因此最有可能是最快的,有点反直觉的也许。干杯, – 2010-10-25 10:42:08

21

你的点子也没什么,但你不能传递一个类型,但一个值(具体来讲,函数指针>另外,通过一个模板策略提供功能 - 这是一个好主意,阅读现代。 C++设计由安德烈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'; 
} 
+0

+ 1为显示一个体面的解决方案与fn-指针。但我认为这仍然会导致一些运行时间开销,以解引用fn指针与do_work_f()和do_work_g()...的复制和粘贴版本? – 2010-10-25 10:19:59

+1

@Martin:这是一个至关重要的问题 - 所有的优化器。我不会打赌这是内联,而我敢打赌一个政策模板成员.... – 2010-10-25 10:29:19

+0

@Tony - 你可能链接了一些资源(约)描述模板政策的事情,你会采取的方式它为这个问题? – 2010-10-25 10:38:48

相关问题