2017-12-21 150 views
6

Próbuję napisać funkcję, która ma inną funkcję, używając pakietów parametrów i niektórych standardowych reguł dopasowania. Jako przykład:Reguły dopasowania pakietów parametrów z wieloma pakietami

template <typename... TListElems, typename... TVectorElems> 
void goal(void (*fn)(std::list<TListElems>..., std::vector<TVectorElems>...)); 

W celu disambiguate TListElems i TVectorElems, dodałem kilka std::tuple<T...>* więc dzwoniący może być jawne:

template <typename... TListElems, typename... TVectorElems> 
void foo(std::tuple<TListElems...>*, 
     std::tuple<TVectorElems...>*, 
     void (*)(std::list<TListElems>..., std::vector<TVectorElems>...)) 
{ 
    // blah blah blah 
} 

void bar(std::list<int>, std::list<unsigned>, std::vector<float>, std::vector<double>) 
{ 
    // blah blah blah 
} 

int main() 
{ 
    foo((std::tuple<int, unsigned>*) nullptr, 
     (std::tuple<float, double>*) nullptr, 
     &bar); 
} 

Clang szczęśliwie kompiluje to w sposób chciałbym oczekiwać, natomiast g ++ (7.2.1) daje błąd kompilacji:

matching.cpp: In function ‘int main()’: 
matching.cpp:20:13: error: no matching function for call to ‘foo(std::tuple<int, unsigned int>*, std::tuple<float, double>*, void (*)(std::list<int>, std::list<unsigned int>, std::vector<float>, std::vector<double>))’ 
     &bar); 
      ^
matching.cpp:6:6: note: candidate: template<class ... TListElems, class ... TVectorElems> void foo(std::tuple<_Tps ...>*, std::tuple<_Elements ...>*, void (*)(std::list<TListElems>..., std::vector<TVectorElems>...)) 
void foo(std::tuple<TListElems...>*, 
     ^~~ 
matching.cpp:6:6: note: template argument deduction/substitution failed: 
matching.cpp:20:13: note: mismatched types ‘std::vector<TVectorElems>’ and ‘std::list<int>’ 
     &bar); 
      ^

w main, chciałbym spodziewać wywołanie foo wydedukować TListElems jak <int, unsigned> i TVectorElems jako <float, double>, prowadząc fn być typu void (*)(std::list<int>, std::list<unsigned>, std::vector<float>, std::vector<double>) (sposób rzeczy działają, gdy istnieje tylko jeden pakiet lub gdybym ręcznie napisany przeciążenie).

§14.8.2.5/10 jest najbliższy Standard przychodzi jawnie zapobiegając przykład foo z pracy:

[Note: A function parameter pack can only occur at the end of a parameter-declaration-list (8.3.5). -end note]

std::list<TListElems>... trochę fn Wygląda na to naruszałoby tę notatkę, ale to nie jest do końca jasne .

Pytanie brzmi: Kto ma rację? GCC, Clang, czy coś innego?

Odpowiedz

3

myślę dzyń jest tutaj.

W void (*)(std::list<TListElems>..., std::vector<TVectorElems>...), TListElems... jest a non-deduced context, co sprawia TVectorElems... także a non-deduced context. Ale oba zestawy parametrów są dedukowalne z dwóch argumentów krotek i oczekuje się, że będą w stanie tutaj również uzyskać tylko use that deduction result.

Złożyłem gcc bug 83542.

+0

§17.9.2.5/6 podaje powód, dla którego działa rozwiązanie Jarod42 (w szczególności: "Jeśli typ jest określone jako 'void f (nazwa_typowa A :: B, A )', 'T' w' A :: B' nie jest wydedukowane, ale 'T' w' A 'jest wydedukowane "), ale jest dla mnie dwuznaczne, jeśli Clang lub GCC rzeczywiście ma właściwą interpretację. –

2

można uszczęśliwiać oba kompilatory z nieprzestrzegania typu wywnioskować:

template <typename T> 
struct non_deducible { 
    using type = T; 
}; 

template <typename T> using non_deducible_t = typename non_deducible<T>::type; 


template <typename... TListElems, typename... TVectorElems> 
void foo(std::tuple<TListElems...>*, 
     std::tuple<TVectorElems...>*, 
     void (*)(non_deducible_t<std::list<TListElems>>..., 
        non_deducible_t<std::vector<TVectorElems>>...)) 
{ 
    // blah blah blah 
} 

Demo

+0

Po prostu użyłbym 'non_deducible_t' na sam typ wskaźnika funkcji. Tak więc 'non_deducible_t ..., std :: vector ...)> *' – Yakk