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(この場合、すなわち単一int)の明示的な引数置換後Uを推定することができなければなりません。

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

パラメータパックT非演繹 [temp.deduct.type]p5

に係る非推定コンテキストに既に存在するので上記同様nondeduced_tトリックなしで動作することが期待される

コンテキストは次のとおりです。

  • 関数のパラメータパラメタ宣言リストの最後には現れない。

残念ながら、私がテストなしコンパイラ(G ++ /打ち鳴らす)がコードを受け入れません。 特に以下のようなものはg ++ & clangで動作します。

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

そして再び、これは両方の上では動作しません:

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

は私の予想が間違ってますか? 非推測コンテキスト[temp.deduct.type]p5一つによって

+0

ここで少し勉強してください。私は 'template void f(void(*)(nondeduced_t ...、U)){}'は、variadicパラメータパックが最初に出現しているため。 – AndyG

+1

@AndyG from cppreference:[プライマリクラステンプレートでは、テンプレートパラメータパックは、テンプレートパラメータリストの最後のパラメータでなければなりません。関数テンプレートでは、次のすべてのパラメータを関数引数から導き出すことができるか、または既定の引数を持つことができるという条件で、テンプレートパラメータパックがリストの先頭に表示されます(http://en.cppreference.com/w/cpp/language/ parameter_pack) – jaggedSpire

+0

これはspeccccによって明示的に指定されていないようです –

答えて

0

パラメータ宣言リストの最後に発生していない関数のパラメータパックです。

テンプレート関数の最後の引数として表示されないパラメータパックは決して推論されませんが、控除を無効にするパラメータタイプを指定することは完全に正しいです。例えば

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. 関数の引数の順序は、パラメータパックの種類を引き起こす非推測コンテキストを作成するには機能fに記載されているパターンのTは決して推論されません。

  2. テンプレートパラメータTは( nondeduced_t例えば)のみの関数の引数で修飾子として表示され、直接(引数控除を許可する)関数の引数として指定されていません。

コードを作るためには、

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

f(g); 

またはテンプレートパラメータの順序を変更し、指定したとして、あなたが持っているのいずれか、それは nondeduced_t、間接を忘れているように、パラメータパックの拡大を置くコンパイル関数呼び出しのテンプレート引数として、

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

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

これらは意図的に質問で推論されていません。前提条件を変更して質問に答えることはできません。 – Jamboree

関連する問題