2016-03-29 20 views
8

Poniższy kod:gcc vs zachowania brzękiem na częściowej specjalizacji z zmiennej liczbie argumentów argumentów Dodatkowo, polecane argument samego typu

#include <cstddef> 

template <size_t N, 
      typename T, 
      T first, 
      T... rest> 
struct A { 
}; 

template<typename T, 
     T... args> 
struct A<0, T, args...> { 
}; 

int main() { 
    A<0, int, 1> a0; 
    A<2, int, 1, 2> a2; 
    return 0; 
} 

... nie skompilować z g++ (wersja 5.1.0 i 5.3.0) ze względu na:

error: partial specialization is not more specialized than the primary template because it replaces multiple parameters with a pack expansion

... ale kompiluje się z clang.

Czy można zadeklarować takie częściowe specjalizacje?

Uwaga boczna: W rzeczywistości specjalizacja jest niebezpieczna, ponieważ A<0, int> nie kompiluje się z obydwoma kompilatorami (błędna liczba argumentów szablonu).

+0

Aby umożliwić '' a <0, int>, musisz zmienić pierwszy szablon. jest już za późno na specjalizację. – Jarod42

+0

@ Jarod42 Tak Wiem, że takie tworzenie szablonu jest błędne, pytam o częściową specjalizację z tylko 'T ... args' podnoszącym błąd w' g ++ 'ale nie' clang' (ponownie zorganizuj pytanie do zrobienia jaśniej). – Holt

+2

GCC ma rację. Jest to źle sformułowane na [DR 1495] (http://wg21.link/cwg1495) (nieco nie zaskakujące, ponieważ zostało zgłoszone przez opiekuna GCC). –

Odpowiedz

8

gcc jest poprawny, kod jest źle sformułowany, ponieważ specjalizacja nie jest w rzeczywistości bardziej wyspecjalizowana.


Zasada z [temp.class.spec] to (jak na skutek DR 1495, h/t TC link):

Within the argument list of a class template partial specialization, the following restrictions apply: [...] The specialization shall be more specialized than the primary template (14.5.5.2).

W celu określenia, że ​​to byłoby przepisz dwa syntetyzowane szablony funkcji:

template <size_t N, class T, T first, T... rest> 
void __f(A<N, T, first, rest...>); // primary 

template <class T, T... args> 
void __f(A<0, T, args...>);   // specialization 

a następnie przejdź przez zasady częściowego zamawiania. To z kolei polega na syntezowaniu nowych typów/wartości dla każdego z parametrów szablonu i sprawdzaniu, czy dedukcja może odnieść sukces w którymkolwiek kierunku.

Zdecydowanie dedukcja specjalizacji kończy się niepowodzeniem z pierwotnym (z powodu N vs 0). W przeciwnym kierunku, od [temp.deduct.partial]:

If A was transformed from a function parameter pack and P is not a parameter pack, type deduction fails.

Ponieważ staramy się wywnioskować T first na opakowaniu, odliczenie nie tak dobrze w tym kierunku. Oznacza to, że żaden ze zsyntetyzowanych szablonów funkcji nie jest bardziej wyspecjalizowany niż inne, co z kolei oznacza, że ​​specjalizacja szablonu klasy nie jest bardziej wyspecjalizowana niż szablon podstawowy. W związku z tym gcc byłoby prawidłowe do odrzucenia.

0

rozważenia:

template <class T, T first, T... rest> 
struct X{}; 

template<class T, T... rest> 
struct X<T, rest...>{}; 

dokładnie ten sam błąd. Od first można interpretować jako pierwszy element pakietu rest, nie ma znaczenia w takiej specjalizacji. Jeśli dodasz first w specjalizacji - cóż, to jest podstawowy szablon. W swojej specjalizacji, choć można dodać first:

//specialization 
template<typename T, 
     T first, 
     T... args> 
struct A<0, T, first, args...> { 
};