G++ Ошибка при частичной разработке шаблонов - программирование

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

Я пишу некоторый TMP-тяжелый код для g++ (версия 4.8.1_1, Macports) и clang++ (версия 3.3, Macports). В то время как g++ отклоняет следующий список кодов с UNBRIDLED FURY, 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++:

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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 стандарта С++ гласит:

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

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

x Вложенное имя-спецификатор типа, который был указан с использованием идентификатора

...

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

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

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