Подтвердить что ты не робот

Расширение пакета для шаблона псевдонима

Кажется, что аргумент pack может быть расширен только вместо параметра пакета шаблона псевдонимов. Это не относится к классу или шаблону функции:

template <class T, class... Args> struct x { using type = T; };

template <class T, class... Args> using x_t     = typename x<T, Args...>::type;
template <class... Args>          using x_fix_t = typename x<Args...>::type;

template <class... Args> auto f(Args...) -> void {
  typename x<Args...>::type v1; // OK
  x_t<Args...> v2; // Error
  x_fix_t<Args...> v3; // OK
}

более простой случай:

template <class T, class U> using y_t = T;

template <class... Args> auto f(Args...) -> void {
  y_t<Args...> v4; // Error
}

Приведенный выше код генерирует ошибку (даже если f никогда не создается экземпляр) как с c++11, так и c++14 в g++ 4.9, g++ 5.1 и clang 3.5.

Почему это не разрешено и каково общее правило? Я не вижу причин ограничивать это. Это кажется очень странным запретом.

Что касается того, почему не писать в качестве x_fix_t с первым вариантом, более ясно, что x_t имеет обязательный первый аргумент. (например, причина, по которой f() не разрешена). Но это не так важно, исправление легко. Остается вопрос: почему?

Ошибка gcc:

error: pack expansion argument for non-pack parameter ‘T’ of
alias template ‘template<class T, class ... Args> using x_t = typename x::type’

ошибка clang:

error: pack expansion used as argument for non-pack parameter of
alias template   x_t<Args...> v2;
4b9b3361

Ответ 1

Это компилируется в GCC 4.8, но не работает в GCC 4.9, что свидетельствует о том, что оно связано с DR1430 и отчет об ошибке # 59498. Исправление, предложенное Роем Хрихфилдом, является тем же самым, что и у вас:

Rewriting the code to use a struct succeeds:

template <typename T, typename ...>
struct alias { using type = T; };

template <typename ...T>
using variadic_alias = typename alias<T...>::type;

Кроме того, Джейсон Меррилл уточняет, почему он должен потерпеть неудачу:

На самом деле, нет, это проблема Core 1430; нет способа mangle variadic_alias без упоминания имени псевдонима шаблоны в качелях, и они должны быть полностью прозрачный. Это работает только в 4.8 случайно, потому что проверка отключено для выпуска.

В отчете об ошибках больше не обсуждается, поэтому мы можем обратиться к DR1430:

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

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

template<class T, class U, class V>
struct S {};

template<class T, class V>
using A = S<T, int, V>;

template<class... Ts>
void foo(A<Ts...>);

Невозможно выразить A в терминах S, поэтому нам нужно провести на А, пока мы не заменим Ts, и, следовательно, должен быть обработан в mangling.

В настоящее время EDG и Clang отклоняют этот тест, жалуясь на слишком несколько аргументов шаблона для A. g++ тоже, но я думал, что это Жук. Однако в списке ABI Джон Спайсер утверждал, что это должно быть отвергнуто.

(См. также выпуск 1558.)

Заметки из собрания в октябре 2012 года:

По мнению CWG, это использование должно быть запрещено, запрет использования шаблона псевдонима, когда зависимый аргумент не может просто подставляться непосредственно в идентификатор типа.

Дополнительное примечание, апрель, 2013:

В другом примере рассмотрим:

  template<class... x> class list{};
  template<class a, class... b> using tail=list<b...>;
  template <class...T> void f(tail<T...>);

  int main() {
    f<int,int>({});
  }

При обработке этого примера существует дисперсия реализации.

В других словах это постоянная проблема без какого-либо разрешения (AFAIC).