13

這類似於question,但更具體的情況。這一次,沒有編譯器按預期工作。模板參數扣除參數類型的函數指針涉及非推斷參數包

template<class T> 
struct nondeduced 
{ 
    using type = T; 
}; 

template<class T> 
using nondeduced_t = typename nondeduced<T>::type; 

template<class... T, class U> 
void f(void(*)(nondeduced_t<T>..., U)) {} 

void g(int, char) { } 

int main() 
{ 
    f<int>(g); // error? 
} 

在上面的例子中,參數包T不能推斷出,但是編譯器應該能夠明確後參數代替包T推斷U(即單int在這種情況下)。

上述預計沒有nondeduced_t特技工作,以及:

template<class... T, class U> 
void f(void(*)(T..., U)) {} 

由於參數包T根據 [temp.deduct.type]p5

非推斷已經處於非推導出上下文背景是:

  • 函數paramete r包不會在參數聲明列表的末尾出現。

不幸的是,我沒有測試過編譯器(g ++/clang)接受代碼。 值得注意的是,下面的代碼可以在g ++ & clang上運行。

template<class... T> 
void f(void(*)(nondeduced_t<T>..., char)) {} 

再次,這並不在兩個工作:

template<class... T> 
void f(void(*)(T..., char)) {} 

是我的期望錯了嗎?

+0

有人請幫助我在這裏學習一點。我會認爲'template void f(void(*)(nondeduced_t ...,U)){}'是不合格的,因爲可變參數包首先出現。 – AndyG

+1

來自cppreference的@AndyG:[在主類模板中,模板參數包必須是模板參數列表中的最後一個參數。在函數模板中,如果可以從函數參數中推導出所有以下參數,或者具有默認參數,那麼模板參數包可以出現在列表中較早的位置](http://en.cppreference.com/w/cpp/language/ parameter_pack) – jaggedSpire

+0

看來,這並不是specccc –

回答

0

通過非推導出上下文[temp.deduct.type]p5一個是

並不以所述參數聲明列表的末尾發生的函數參數包。

不會出現作爲模板函數的最後一個參數出現的參數包,但是完全正確指定禁用扣除的參數類型。 e.g

template<class T1, class ... Types> void g1(Types ..., T1); 

g1<int, int, int>(1,2,3); // works by non-deduction 
g1(1,2,3)     // violate the rule above by non-deduced context 

但是改變函數參數即使在離開模板參數,因爲它們是,除去非推斷情境條件,打破參數包的無限擴大的順序。例如

template<class T1, class ... Types> void g1(T1, Types ...); 
g1(1,2,3)     // works because its a deduced context. 

這裏有兩種原因,你的代碼不編譯:

  1. 函數參數的順序創建非推斷上下文引起的參數包的類型T以功能中所述的模式進行,將永遠不會推斷出f

  2. 模板參數T只出現在函數自變量的限定符(例如nondeduced_t),而不是直接指定作爲函數參數(其允許參數推導)。

爲了使代碼編譯,你要麼把參數包,因爲它是忘記nondeduced_t間接的擴展,

template<class... T,class U> 
void f(void(*)(U,T...)) { } 

f(g); 

或改變模板參數的順序,並指定函數調用模板參數,如

template<class U,class... T> 
void f(void(*)(U,typename nondeduced<T>::type...)) {} 

f<int,char>(g);  
+0

它們在問題中被有意地推斷出來。您無法通過更改先決條件來回答問題。 – Jamboree