2010-10-25 88 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

相關問題