13

Jest to podobne do question, ale bardziej konkretny przypadek. Tym razem żaden kompilator nie działa zgodnie z oczekiwaniami.Odliczanie argumentów szablonów dla parametru typu wskaźnika funkcji zawierającego nieopublikowany pakiet parametrów

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? 
} 

W powyższym przykładzie, opakowanie parametr T nie można wywnioskować, ale kompilator powinien móc wyprowadzić U po wyraźne argumenty podstawieniem opakowanie T (to pojedynczy int w tym przypadku).

Oczekuje się, że wyżej pracować bez nondeduced_t sztuczki, a także:

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

Ponieważ opakowanie parametr T już w nie-wywnioskować kontekście według [temp.deduct.type]p5

Non-wywnioskować są to:

  • Parametr funkcji r paczka, która nie występuje na końcu listy deklaracji parametrów.

Niestety, nie testowałem kompilator (g ++/dzyń) zaakceptować kod. W szczególności coś jak poniżej działa zarówno na g ++ & clang.

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

I znowu, to nie działa na oba:

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

Czy moje oczekiwanie nie tak?

+0

Ktoś pomóż mi się trochę nauczyć. Myślałem, że 'szablon void f (void (*) (nondeduced_t ..., U)) {}' było źle sformułowane, ponieważ pakiet parametrów variadic pojawia się jako pierwszy . – AndyG

+1

@AndyG from cppreference: [W szablonie podstawowej klasy, pakiet parametrów szablonu musi być końcowym parametrem na liście parametrów szablonu. W szablonie funkcji pakiet parametrów szablonu może pojawić się wcześniej na liście pod warunkiem, że wszystkie poniższe parametry można wyprowadzić z argumentów funkcji lub mają domyślne argumenty] (http://en.cppreference.com/w/cpp/language/ parameter_pack) – jaggedSpire

+0

Wygląda na to, że nie jest to jednoznacznie określone przez specyfikację –

Odpowiedz

0

Przez [temp.deduct.type]p5 jednego z non-wyprowadzona-context jest

Funkcja Parametr paczka, która nie występuje na końcu parametru deklaracja liście.

Pakiety parametrów, które nie pojawiają się jako ostatni argument funkcji szablonu, nigdy nie są wyprowadzone, ale całkowicie słuszne jest określenie typów parametrów wyłączających odliczanie. np

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 

Ale zmieniając kolejność argumentów funkcja wychodzenia parametry szablonu, ponieważ są one, usuń non-wywnioskować stan kontekstowe i przełamać nieskończonej ekspansji parametrów paczki. np

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

Są tam dwa powody kod nie kompilacji:

  1. Kolejność argumentów funkcji tworzą non-dedukcji-kontekst które powodują rodzaj opakowania parametru T we wzorze podanym w funkcji f nigdy nie zostanie wydedukowane.

  2. Szablon parametr T pojawia się tylko jako kwalifikacyjne w argumentów funkcji (np nondeduced_t) a nie bezpośrednio określonych jako argument funkcji (co pozwala na wydedukowanie argument).

aby kod skompilować masz albo umieścić rozszerzenie pakietu parametrów jak to jest zapominając nondeduced_t pośrednie, jak

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

f(g); 

lub zmianę kolejności parametrów szablonu i określić Argument szablonu przy wywołaniu funkcji, jako

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

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

Zostały one nieumyślnie wydedukowane w pytaniu. Nie możesz odpowiedzieć na pytanie, zmieniając wymaganie wstępne. – Jamboree