Частная специализация шаблона
Может кто-нибудь объяснить, почему эти две специализации неотличимы от компилятора (gcc 4.5.1 @ideone)
http://ideone.com/9tNux
template <typename... T> struct S;
template<typename A, typename B, typename... C>
struct S<A, B, C...> {
int f() {return 1;}
};
template<typename... A, typename... C>
struct S< S<A...>, C...> {
int f() {return 2;}
};
и когда я пытаюсь создать экземпляр S<S<a, b>, a, b> o2;
, компилятор жалуется:
prog.cpp:20:21: error: ambiguous class template instantiation for 'struct S<S<a, b>, a, b>'
prog.cpp:6:22: error: candidates are: struct S<A, B, C ...>
prog.cpp:11:33: error: struct S<S<A ...>, C ...>
prog.cpp:20:21: error: aggregate 'S<S<a, b>, a, b> o2' has incomplete type and cannot be defined
И когда последняя специализация изменена на:
template<typename... A, typename B, typename... C>
struct S< S<A...>, B, C...> {
int f() {return 2;}
}
все работает нормально.
Ответы
Ответ 1
Мое понимание проблемы:
typedef S<S<a, b>, c, d> S2;
Здесь S<a,b>
лучше соответствует второй специализации. Однако c, d
лучше подходит для остальных аргументов первой специализации (единственный список arg + list vs list). Следовательно, это 1:1.
Если вы комментируете в B
во второй специализации, то вторая специализация лучше соответствует, потому что она более специализирована для первого аргумента (S<...>
), а остальные одинаково хороши.
Ответ 2
Я сделал это беспорядок; теперь это должно быть хорошо, но кредит связан с @UncleBens ниже, кто правильно понял (и должен получить "accept" ).
Без B
в вашей третьей версии у вас есть две частичные специализации, которые одинаково специфичны, когда вы создаете экземпляр S<S<X,Y,Z>, T1, T2, T3>
:
- Первый PS:
A = S<X,Y,Z>
, B = T1
, C... = T2, T3
.
- Второй PS без
B
: A... = X,Y,Z
, C... = T1, T2, T3
.
- Второй PS с
B
: A... = X,Y,Z
, B = T1
, C... = T2, T3
.
Это не устанавливает сопоставимые элементы в упорядочении частичной специализации!
Обратите внимание, что вы можете сказать template <typename ...> struct S;
и template <typename A, typename ...B> struct S<A, B...>;
, а второй - более конкретный, чем первый, поскольку он имеет больше невариантных параметров.
Но, с другой стороны, без B
, когда вы говорите S<S<X,Y,Z>,T1,T2,T3>
, тогда первый аргумент лучше подходит во втором PS, но остальные аргументы лучше подходят для первого PS. Тем не менее, при использовании B
второй PS более конкретный.
Сравните это с частичной специализацией, которая является более конкретной:
template <typename ...A, typename B, typename ...C>
struct S<B, std::tuple<C...>, std::tuple<C...>> { /* ... */ };
Теперь ясно, соответствует ли данный экземпляр специализации или только общей форме. Специализация имеет фиксированное количество параметров (3), поэтому выигрывает по другой специализации с переменным числом аргументов.