2015-06-03 64 views
6

爲什麼F不能推導爲proxy()無法推斷出作爲函數的模板參數

它應該是可能的,因爲我限制它 - 僅適用於返回int的函數。

#include <utility> 
#include <iostream> 
#include <type_traits> 
using namespace std; 

int foo(int bar) { 
    cout << "int" << endl; 
    return 2; 
} 

float foo(float bar) { 
    cout << "float" << endl; 
    return 1; 
} 

template <typename F, typename... Args> 
typename enable_if< 
    is_same< 
     typename result_of<F(Args...)>::type, 
     int 
     >::value, 
    typename result_of<F(Args...)>::type 
    >::type 
proxy(F func, Args&&... args) { 
    return func(forward<Args>(args)...); 
} 

int main() { 
    proxy(foo, 5); 
} 

以下是錯誤:

b.cpp:29:17: error: no matching function for call to 'proxy(<unresolved overloaded function type>, int)' 
b.cpp:24:1: note: template argument deduction/substitution failed: 
b.cpp:29:17: note: couldn't deduce template parameter 'F' 
+0

由於有功能的兩個重載...編譯器不能推斷上的基本價值未來(下一個)函數的參數...'代理(static_cast (foo),5);'會在這裏做的伎倆 –

回答

4

問題是這樣的:

proxy(foo, 5); 

編譯器試圖推斷的foo類型,但有2點過載。當然,它可以從5推導出Args...,但foo的類型仍然是不可推導的,因爲編譯器不知道在執行類型推導時要選擇哪個超載。

注意,編譯器需要知道的F類型的函數的簽名,也就是在這裏,所以SFINAE做它的神奇:

is_same< 
    typename result_of<F(Args...)>::type, 
    int 
>::value, 

是絕對沒有辦法爲它正確地推斷類型從proxy(foo, 5)調用F,所以SFINAE不能踢。作爲一個方面說明,注意到C++不能僅基於返回類型重載。因此,您將無法單獨根據返回類型區分具有相同名稱的兩個函數。你需要以某種方式強制一個參數匹配,它將SFINAE輸出非候選重載。

某種聯繫:Deducing the return type of a standalone function

,並從標準相關的報價,強調雷(感謝@TC指點出來):從一個函數調用[溫度

14.8.2.1推導模板參數.deduct.call] /(6.2)

(6) When P is a function type, pointer to function type, or pointer to member function type:

  • (6.1) If the argument is an overload set containing one or more function templates, the parameter is treated as a non-deduced context.

  • (6.2) If the argument is an overload set (not containing function templates), trial argument deduction is attempted using each of the members of the set. If deduction succeeds for only one of the overload set members, that member is used as the argument value for the deduction. If deduction succeeds for more than one member of the overload set the parameter is treated as a non-deduced context.

+0

但爲什麼不嘗試每一個,看看它會得到多少模板實例化/替代? 有沒有辦法解決這個問題,而沒有明確的轉換? – onqtam

+0

@onqtam我想這太複雜了,因爲編譯器的第一個參數'F'與第二個'Args ...'沒有任何關係。我會試着想一個解決方法。 – vsoftco

+0

這個問題是可重現的沒有參數 - 只有當使用返回類型...我想我應該把一個更簡單的例子 – onqtam

2

在您的例子foo名一組的重載函數,和模板參數推導無法選擇o ne超過另一個,因爲它們都是相等的等級。

在推導出F之後,您的SFINAE約束檢查纔會啓動,因此從重載解析集合中刪除float foo(float)沒有任何幫助。

假設你重命名函數返回floatfoof,那麼你的例子將編譯。但是,如果您嘗試將proxyfoof作爲函數參數進行調用,則代碼將再次無法編譯,這次是因爲enable_if約束。

爲了讓您的例子在當前狀態下進行編譯,您必須消除歧義這foo要傳遞到proxy

proxy(static_cast<int(*)(int)>(foo), 5); 
+0

我想我還沒有完全理解SFINAE,因爲我認爲它會幫助我在這裏... – onqtam

相關問題