2014-10-03 36 views
1

假設以下兩個功能可能會或可能不會被用戶提供:選擇功能通過元編程

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

在我的實現,我想打電話給foo(int)如果用戶定義它,否則foo()。這可以如下進行:

template<class Int> auto call_foo(Int i) -> decltype(foo(i)) { return foo(i); } 
template<class... Int> void call_foo(Int... i) { return foo(); } 

但是,如果我們想反其道而行之,即寧願foo()超過foo(int),下面的天真嘗試不起作用。

template<class Int> auto call_foo(Int i) -> decltype(foo()) { return foo(); } 
template<class... Int> void call_foo(Int... i) { return foo(i...); } 

的問題是,decltype(foo())不依賴於Int,所以foo()可能不存在不SFINAE結果。

一種可能的解決辦法是要求用戶定義的

void foo(int, void*) { std::cout << "foo int" << std::endl; } 
void foo(void*) { std::cout << "foo void" << std::endl; } 

像這樣無論是,我們總是有foo參數上,我們可以做的「模板與參數包」的把戲。雖然這在技術上解決了這個問題,但它很難看,因爲它要求用戶採取一個額外的參數,這個參數對他/她來說可能並不明顯。那麼有沒有辦法達到同樣的效果沒有的附加參數?

回答

3

以下可能會有所幫助:

template<typename ... Ts> void foo(Ts...) = delete; 
void foo(int) { std::cout << "foo int" << std::endl; } 
//void foo() { std::cout << "foo void" << std::endl; } 

namespace detail 
{ 

struct overload_priority_low {}; 
struct overload_priority_high : overload_priority_low{}; 

template <typename Int> 
auto call_foo(Int i, overload_priority_low) -> decltype(foo(i)) { return foo(i); } 

template <typename Int> 
auto call_foo(Int , overload_priority_high) -> decltype(sizeof(Int), foo()) { return foo(); } 

} 

void call_foo(int i) 
{ 
    return detail::call_foo(i, detail::overload_priority_high{}); 
} 

Live example

+0

它似乎沒有與叮噹 – 2014-10-03 09:00:40

+0

非常有用的技巧,這個標籤繼承。我在這裏清理你的代碼:http://stackoverflow.com/questions/26176516/choose-best-available-function-through-tag-inheritance – gTcV 2014-10-03 09:31:16

+0

@MarcoA .:刪除'= delete'似乎解決了錯誤與叮噹聲。 – Jarod42 2014-10-03 09:44:18

4

不需要SFINAE。只需標準重載分辨率就足夠了。

void call_func(void (*f)(), int) { f(); } // #1 

template<class = void> 
void call_func(void (*f)(int), int x) { f(x); } // #2 

call_func(foo, 1); // #1 is preferred if viable. All others being equal, 
        // non-templates are preferred over templates 
+0

+1。雖然我希望看到一個很好的TMP解決方案,它可以用於用戶指定的優先級。例如,如果他有'N''foo's,它們都取對應數量的'int',並且用戶想要指定'{1,...,N}'的一些置換作爲優先順序。當然,我沒有看到任何實際意義。只是它會導致一些有趣的代碼:) – Pradhan 2014-10-03 08:17:21

+1

您可以使用*標記繼承*來訂購多重過載(並避免模板)。 – Jarod42 2014-10-03 08:23:13

+0

您的解決方案適用於我在問題中描述的情況。不幸的是,在實際的代碼中,我有兩個以上的函數,並不是所有的函數都有相同的名字。然後,您需要SFINAE排除不存在的名稱。 – gTcV 2014-10-03 09:00:48