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

Алиасы шаблонов Variadic в качестве аргументов шаблона

Сначала какой-то код, затем какой-то контекст, затем вопрос:

template <typename T> using id = T;

template <template <typename...> class F, typename... T>
using apply1 = F <T...>;

template <template <typename...> class F>
struct apply2
{
    template <typename... T>
    using map = F <T...>;
};

// ...

cout << apply1 <id, int>() << endl;
cout << apply2 <id>::map <int>() << endl;

Оба clang 3.3 и gcc 4.8.1 скомпилируют это без ошибок, применяя метафайл идентификации к int, поэтому оба выражения оцениваются по умолчанию int (ноль).

Тот факт, что id является template <typename>, а apply1, apply2 ожидает, что a template <typename...> действительно беспокоило меня в первую очередь. Однако это довольно удобно, потому что в противном случае метафоры, такие как apply1, apply2, должны были бы быть гораздо более вовлечены.

С другой стороны, такие псевдонимы шаблонов вызывают серьезные проблемы в реальном коде, которые я не могу воспроизвести здесь: частые внутренние ошибки компилятора для gcc и менее частые неожиданные действия для clang (только в более сложных тестах SFINAE).

После нескольких месяцев проб и ошибок, теперь я устанавливаю и тестирую код на (экспериментальном) gcc 4.9.0, и здесь возникает ошибка:

test.cpp: In instantiation of ‘struct apply2<id>’:
test.cpp:17:22: error: pack expansion argument for non-pack parameter ‘T’ of alias template ‘template<class T> using id = T’
  using map = F <T...>; 
                      ^

Итак, похоже, что этот код был недействителен все это время, но gcc разбился по-разному, а не сообщал об ошибке. Интересно, что в то время как apply1, apply2 кажутся эквивалентными, ошибка сообщается только для apply2 (что на практике гораздо более полезно). Что касается clang, я действительно не могу сказать.

На практике кажется, что у меня нет другого выхода, кроме как пойти с gcc 4.9.0 и исправить код, хотя он станет намного сложнее.

В теории я хотел бы знать, что говорит стандарт: действительно ли этот код? Если нет, используется ли значение apply1 неверно? или только apply2?

ИЗМЕНИТЬ

Просто чтобы уточнить, что все проблемы, которые я имел до сих пор, относятся к псевдонимам шаблонов, а не к шаблонам. Например, рассмотрим следующую модификацию:

template <typename T> struct id1 { using type = T; };

// ...

cout << typename apply1 <id1, int>::type() << endl;
cout << typename apply2 <id1>::map <int>::type() << endl;

Это компилируется и печатает 0 в обоих случаях, на clang 3.3, gcc 4.8.1, gcc 4.9.0.

В большинстве случаев мои обходные пути вводят промежуточную структуру шаблона перед псевдонимом. Тем не менее, я сейчас пытаюсь использовать метафайлы для параметризации общих тестов SFINAE, и в этом случае я должен использовать псевдонимы напрямую, потому что структуры не должны создаваться. Чтобы получить представление, часть фактического кода здесь.

4b9b3361

Ответ 1

ISO С++ 11 14.3.3/1:

Шаблон-аргумент для шаблона-шаблона шаблона должен быть именем шаблона класса или шаблоном алиаса , выраженным как id-expression.

Плюс я не вижу особых исключений для параметров шаблона шаблона.

С другой стороны, такие псевдонимы шаблонов вызывают серьезные проблемы в реальном коде, которые я не могу воспроизвести здесь: частые внутренние ошибки компилятора для gcc и менее частые неожиданные действия для clang (только в более сложных тестах SFINAE).

Корень проблем может быть в других местах. Вы должны попытаться локализовать код, который вызывает внутреннюю ошибку компилятора, - просто удалите несвязанные части один за другим (или используйте какой-то бинарный поиск, т.е. Divide-and-завоевание), и проверьте, не существует ли ошибка на каждом этапе.


Что касается ошибки GCC 4.9.0, попробуйте изменить

template <typename... T>
using map = F <T...>;

к

template <typename... U>
using map = F <U...>;

Возможно, это поможет понять, что видит GCC.