16

Первый некоторый код, то определенный контекст, то возникает вопрос: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; 

Оба лязг 3,3 и GCC 4.8.1 транслируют это без ошибок, применяя metafunction идентичности к int, так как выражения оцениваются по умолчанию int (ноль).

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

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

После нескольких месяцев проб и ошибок, я теперь установить и попробовать код на (экспериментальный) НКУ 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...>; 
        ^

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

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

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

EDIT

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

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

// ... 

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

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

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

+3

Сообщение об ошибке экспериментального GCC 4.9 не имеет для меня смысла, и FWIW Я считаю, что код действителен. –

+0

Связанные? http://stackoverflow.com/q/18724698/420683 – dyp

+0

Спасибо, этот вопрос связан с тем, что шаблоны, касающиеся особых случаев, таких как 'foo',' foo2', 'foo_variadic' и т. д., точно так же, как я планировал исправить код, если нужно. Однако, как я уже писал выше, мои проблемы появляются только с псевдонимами шаблонов. – iavr

ответ

3

ISO C++ 11 14.3.3/1:

A template-argument for a template template-parameter shall be the name of a class template or an alias template, expressed as id-expression.

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

On the other hand, such template aliases cause serious problems in real-world code that I cannot reproduce here: frequent internal compiler errors for gcc, and less frequent unexpected behavior for clang (only in more advanced SFINAE tests).

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


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

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

в

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

Может быть, это поможет понять, что GCC видит.

+0

Спасибо. Я не смог изолировать код, который был ошибочным в прошлом, потому что удаление даже небольших деталей заставило ошибки исчезнуть. С gcc 4.9 это был первый раз, когда я увидел ясное сообщение об ошибке, и я был «счастлив», потому что, если это правда, это может объяснить почти все (хотя каждое решение будет уродливым). Так или иначе, поскольку проблемы все еще существуют, я попытаюсь сделать новый пример с неожиданным результатом в других компиляторах и вернуться с новым вопросом. – iavr

Смежные вопросы