13

Я пишу некоторый TMP-тяжелый код для g ++ (версия 4.8.1_1, Macports) и clang ++ (версия 3.3, Macports). В то время как g ++ отклоняет следующий код с UNBRIDLED FURY, clang ++ компилирует его с grace и splendor.g ++ Ошибка с частичным шаблоном Специализация

  • Какой корреспондент находится справа? (Я сильно подозреваю, что это g ++, но я хочу получить некоторое подтверждение от других, прежде чем отправлять отчет об ошибке.)
  • Есть ли у вас какие-либо простые или изящные обходные решения? (Мне нужно использовать псевдонимы шаблонов, поэтому переключение на структуры, что приводит к г ++ принять код, это не вариант.)

Вот код листинг, сделанный только для вас.

template <class... Ts> 
struct sequence; 

template <int T> 
struct integer; 

// This definition of `extents` causes g++ to issue a compile-time error. 
template <int... Ts> 
using extents = sequence<integer<Ts>...>; 

// However, this definition works without any problems. 
// template <int... Ts> 
// struct extents; 

template <int A, int B, class Current> 
struct foo; 

template <int A, int B, int... Ts> 
struct foo<A, B, extents<Ts...>> 
{ 
    using type = int; 
}; 

template <int B, int... Ts> 
struct foo<B, B, extents<Ts...>> 
{ 
    using type = int; 
}; 

int main() 
{ 
    using t = foo<1, 1, extents<>>::type; 
    return 0; 
} 

Здесь г 's выход:

er.cpp: In function 'int main()': 
er.cpp:39:41: error: ambiguous class template instantiation for 'struct foo<1, 1, sequence<> >' 
    using t = typename foo<1, 1, extents<>>::type; 
             ^
er.cpp:26:8: error: candidates are: struct foo<A, B, sequence<integer<Ts>...> > 
struct foo<A, B, extents<Ts...>> 
     ^
er.cpp:32:8: error:     struct foo<B, B, sequence<integer<Ts>...> > 
struct foo<B, B, extents<Ts...>> 
     ^
er.cpp:39:43: error: 'type' in 'struct foo<1, 1, sequence<> >' does not name a type 
    using t = typename foo<1, 1, extents<>>::type; 
             ^

Вот лязг ++ ++ s выход:

Спасибо за вашу помощь!

+4

'+ 1' для шуток в одиночку :) Я также поставил бы, что Кланг здесь. –

+0

«typename» в 'main' is uneded –

+0

@ DavidRodríguez-dribeas Спасибо, это стало привычкой ... –

ответ

7

Это похоже на ошибку g ++, потому что понятно, что foo<B, B, extents> более специализирован, чем foo<A, B, extents> (последнее может соответствовать всем, что было раньше, но не наоборот), поэтому компилятор должен выбрать эту специализацию.

Как вы отметили, изменение extents из шаблона-шаблона в шаблон шаблона решает эту проблему.

3

вопрос сводится, если я понял правильно определить ли один из следующих специализаций шаблона является более специализированным, чем другой:

template <int A, int B, class Current> 
struct foo; 

template <int A, int B, int... Ts> 
struct foo<A, B, extents<Ts...>> 
{ 
    using type = int; 
}; 

template <int B, int... Ts> 
struct foo<B, B, extents<Ts...>> 
{ 
    using type = int; 
}; 

И ответ да, для любой комбинации параметров, разрешены во второй специализации, одна и та же комбинация допускается в первом случае путем создания аргументов шаблона A == B. С другой стороны, любой экземпляр первой специализации шаблона, по которому A != B не может быть совпадением для второй специализации, поэтому второй является строго более специализированным, чем первый.

0

Я верю, что g ++ может быть правильным. Линия

using t = foo<1, 1, extents<>>::type 

используют параметры шаблона в не выводятся контекст, поэтому он не может использовать фактические значения, указанные для параметров шаблона для разрешения неоднозначности, только их типов, и что не является достаточным.

Раздел 14.8.2.5, пункт 4 стандарта С ++ говорит:

В большинстве случаев, значения типов, шаблоны, и не типа, которые используются для составления P участвовать в аргументу шаблона вывода. То есть они могут использоваться для определения значения аргумента шаблона, и определяемое таким образом значение должно соответствовать значениям, определенным в другом месте.Однако в определенных контекстах значение не участвует в выводе типа, но вместо этого использует значения аргументов шаблона, которые были либо выведены в другом месте, либо явно указаны. Если параметр шаблона используется только в не выводимых контекстах и ​​явно не указан, вывод аргумента шаблона не выполняется.

В не-выведены контекстах:

х вложенное имени-спецификатор типа, который был определен с помощью квалифицированного идентификатора

...

Раздела 14.8.2.4 пункт 11 говорит:

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

Итак, мы находимся в невыводимом контексте, а это значит, что все аргументы шаблона должны иметь значения. Так что, если экстенты <> не могут прибить тип, то результат будет неоднозначным в соответствии со стандартом. Правдоподобно?

+0

Выражения «P»: 'A',' B', 'экстенты '. Выражения «А»: «1», «1», «экстенты» <> ». Нет выражения «P» использует любой параметр шаблона в невыводимом контексте. – aschepler

+0

Не делает ли тип :: на конце идентификатором? –

+0

Да, 'foo <1, 1, экстенты <>> :: type' - это квалифицированный идентификатор. Но он не использует никаких параметров шаблона. Он содержит некоторые аргументы шаблона («A» в 14.8.2). Аргументы в id-критериях сравниваются с вычитанием; они не выводятся. – aschepler