2012-03-23 73 views
3

A C++ 11模板函數,它接受一個功能對象參數,如:促進C++重載的函數指針函數對象的

template <typename F, typename T> 
auto foo(F f, T x) -> decltype(f(x)) { 
    return f(x); 
} 

可以採取函數,例如:

int succ(int i) { return i+1; } 

並應用到foosucc獲得的10結果:

foo(succ,9); 

重載˚F與 「不能推導出模板參數F」

foo(std::sin,0.5); 
在GCC(4.7)

:unctions不工作,sin,例如,將失敗。

(提供sin<double>僅涉及複雜類型BTW。)是的,我能結構是正確的了:

template <typename T> 
struct Sin { 
    T operator()(T x) { return std::sin(x); } 
}; 

一點點:

foo(Sin<double>(),0.5); 

我的問題是,是否有替代這避免了對這種新定義的需求;僅可在foo的呼叫地點使用?

+0

'static_cast'是一種選擇,雖然顯然不是理想的選擇。 – ildjarn 2012-03-23 00:18:22

+0

你是什麼意思'罪'不起作用?它編譯罰款 – 2012-03-23 00:22:48

+0

@VJovic:你是什麼意思,我的意思是?它不會編譯。你刪除的答案雖然。我不知道爲什麼。 – user2023370 2012-03-23 00:27:09

回答

8

函數指針,你可以簡單地讓用戶鍵入簽名:

template<class F, class T> 
void foo(F f, T x){ 
    f(x); 
} 

void bar(int){} 
void bar(double){} 

int main(){ 
    foo<void(int)>(bar, 5); 
} 

Live example on Ideone

foo將在替換後爲void foo(void f(int), int x),這與foo(void (*f)(int), int x)相同。這提供了一個所謂的「調用上下文」,它允許編譯器選擇正確的過載。顯然,如果第一個模板參數是函數,這隻會有效。要解決此限制,並使它看起來更好(恕我直言,至少),你可以提供一個簡單的輔助功能:

template<class F> 
auto get_overload(F f) -> decltype(f) { return f; } 

其實,你只能超負荷的參數類型,但你無法剔除出需要讓用戶輸入返回類型,因爲這會再次禁用調用上下文,因爲需要推導出類型。

既然你最有可能(或肯定)只希望這個函數指針,你可以把它改成這樣:

template<class F> 
F* get_overload(F* f){ return f; } 

它仍然是完全一樣的。第一個版本不能只有F作爲返回類型的唯一原因是Fvoid(int)如果您使用get_overload<void(int)>(bar)調用它,並且該標準不允許您返回函數(是的,那是函數類型)。功能指針轉換功能(void(int) - >void(*)(int))僅適用於參數。


因爲無論出於何種原因@VJovic刪除他的回答,我就在編輯這個:

實際上,你可以使用,而不是get_overload功能簡單的拉姆達。這將是大約相同的長度字符明智,更方便,更清晰。它也會更有效率,因爲不包含(函數)指針,編譯器完全能夠內聯該調用。

foo([](int i){ return bar(i); }, 5); 
+0

+1,重要的是要注意,這是表達式的使用產生影響的唯一語言位置。另外,另一種解決方案是轉換函數指針:'foo((void(*)(int))bar,5)'[這是一個靜態轉換],可以用作* any * template參數 – 2012-03-23 02:14:21

+0

+1 ''get_overload'。尼斯,非常好,還有一些比*另一個*'static_cast'更友好。 – 2012-03-23 08:51:52

+1

+1,因爲他很親切,並加入了VJovic的回答。 – ildjarn 2012-03-23 21:22:32