Частичная специализация шаблона - PullRequest
10 голосов
/ 09 августа 2011

Может кто-нибудь объяснить, почему эти две специализации неразличимы для компилятора (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;}
}

все отлично работает.

Ответы [ 2 ]

9 голосов
/ 09 августа 2011

Мое понимание вопроса:

typedef S<S<a, b>, c, d> S2;

Здесь S<a,b> лучше соответствует второй специализации.Однако c, d является лучшим соответствием для оставшихся аргументов первой специализации (один аргумент + список против списка).Следовательно, оно равно 1: 1.

Если вы прокомментируете B во второй специализации, то вторая специализация лучше подходит, потому что она более специализирована для первого аргумента (S<...>), а остальные одинаковохорошо.

8 голосов
/ 09 августа 2011

Я испортил это;теперь все должно быть в порядке, но заслуга @UncleBens ниже, который правильно понял (и должен получить «принять»).


Без 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), поэтому она выигрывает у другой специализации с переменным числом аргументов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...