Частичная специализация вариационных шаблонов - PullRequest
44 голосов
/ 06 декабря 2011

Рассмотрим следующий шаблон класса 'X' и его частичные специализации.

template <class ...Types>
struct X {};               // #1

template <class T1>
struct X<T1> {};           // #2

template <class T1, class ...Types>
struct X<T1, Types...> {}; // #3

X<int> x;                  // #2 or #3 ?

Я подозреваю, что X неоднозначно. Это потому что:

Очевидно, что и № 2, и № 3 более специализированы, чем № 1, № 2 и № 3 теперь сравниваются. В соответствии с 14.5.5.2, давайте рассмотрим, какие из следующих # 2 'и # 3' являются более специализированными.

template <class T1>
void f(X<T1>);             // #2'

template <class T1, class ...Types>
void f(X<T1, Types...>);   // #3'

Согласно 14.8.2.4, первый шаг - это вывод аргумента шаблона с использованием # 2 'в качестве шаблона аргумента и # 3' в качестве шаблона параметра. Учитывая, что единственным типом аргумента является X , выведенный T1 является A1, а Types пуст.

A = X<A1>, P = X<T1, Types...>  =>  T1 = A1, Types = {}

Второй шаг выполняется с использованием # 3 'в качестве шаблона аргумента и # 2' в качестве шаблона параметра. Учитывая, что единственным типом аргумента является X , в соответствии с 14.8.2.5/9 (обратите внимание, что этот параграф недавно пересмотрен N3281), Args просто игнорируется, выведенный T1 равен A1, и вывод аргумента завершается успешно.

A = X<A1, Args...>, P = X<T1>  =>  T1 = A1 (Args is ignored)

Наконец, двунаправленный вывод аргументов завершился успешно. Так что # 2 так же специализирован, как и # 3. В заключение, X является неоднозначным.

Мой вопрос: «Правильно ли мое толкование?»

Если эта интерпретация верна, определение 'std :: common_type' в 20.9.7.6/3 неуместно.

template <class ...T>
struct common_type;            // #1

template <class T>
struct common_type<T>          // #2
{
    typedef T type;
};

template <class T, class U>
struct common_type<T, U>       // #3
{
    typedef
        decltype(true ? declval<T>() : declval<U>())
    type;
};

template <class T, class U, class ...V>
struct common_type<T, U, V...> // #4
{
    typedef typename
        common_type<typename common_type<T, U>::type, V...>::type
    type;
};

Когда используется common_type , # 3 и # 4 неоднозначны.

Примечание: в первом примере GCC 4.7.0 (снимок) и Clang 3.0 выбирают # 2. Однако эти компиляторы настолько ненадежны, что не следуют другим изменениям, внесенным N3281.

1 Ответ

8 голосов
/ 20 декабря 2011

14.8.2.4, раздел 11 (я имею в виду черновик N3242).

В большинстве случаев все параметры шаблона должны иметь значения для успешного вычета, но для целей частичного упорядочения шаблонПараметр может остаться без значения, если он не используется в типах, используемых для частичного упорядочения.[Примечание. Параметр шаблона, используемый в невзаимодействующем контексте, считается использованным.- конец примечания] [Пример:

template <class T> T f(int); // #1
template <class T, class U> T f(U); // #2
void g() {
f<int>(1); // calls #1
}

В вашем случае будет использоваться # 3.

...