Ошибка g ++ с частичной специализацией шаблонов

Я пишу некоторый TMP-тяжелый код для g ++ (версия 4.8.1_1, Macports) и clang ++ (версия 3.3, Macports). В то время как g ++ отклоняет следующий листинг кода с НЕВЕРОЯТНАЯ ПУТЬ, clang ++ компилирует его Грейс а также пышность.

  • Какой компилятор в праве? (Я сильно подозреваю, что это 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;
}

Вот вывод g ++:

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;
^

Вот вывод clang ++:

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

13

Решение

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

Как ты сам заметил, меняешься extents от псевдонима шаблона до шаблона класса, решает проблему.

7

Другие решения

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

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

3

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

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

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

Раздел 14.8.2.5, параграф 4 стандарта C ++ гласит:

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

Неведуемые контексты:

x Спецификатор вложенного имени типа, указанного с помощью квалифицированного идентификатора.

Раздел 14.8.2.4, пункт 11 гласит:

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

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

0
По вопросам рекламы [email protected]