33

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

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() не допускается). Но это не так важно, исправление легко. Остается вопрос: почему?

НКУ ошибка:

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

лязг ошибка:

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

Информация здесь актуальна, я думаю: http://stackoverflow.com/q/24433658/4326278 – bogdan

+0

Кроме того, для того, что стоит, MSVC 12 и 14 RC скомпилируют это без каких-либо диагностических функций (кроме обычных предупреждений о непривязанных переменные) - «дисперсия реализации», как говорится. – bogdan

+0

Работает нормально в g ++ 4.8.2. –

ответ

14

компилируется в GCC 4.8, но не в GCC 4.9, что является доказательством того, что это связано с DR1430 и bug report #59498. Исправление предложил Рой Chrihfield точно такой же один, как у вас:

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; 

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

Actually, no, this is very much a Core 1430 issue; there's no way to mangle variadic_alias without mentioning the name of an alias template in the mangling, and they're supposed to be entirely transparent. This only works in 4.8 by accident because checking is disabled for the release.

Никакое дальнейшее обсуждение не существует в сообщении об ошибке, поэтому мы может обратиться к DR1430:

Originally, a pack expansion could not expand into a fixed-length template parameter list, but this was changed in N2555. This works fine for most templates, but causes issues with alias templates.

In most cases, an alias template is transparent; when it's used in a template we can just substitute in the dependent template arguments. But this doesn't work if the template-id uses a pack expansion for non-variadic parameters. For example:

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...>); 

There is no way to express A in terms of S, so we need to hold onto the A until we have the Ts to substitute in, and therefore it needs to be handled in mangling.

Currently, EDG and Clang reject this testcase, complaining about too few template arguments for A. G++ did as well, but I thought that was a bug. However, on the ABI list John Spicer argued that it should be rejected.

(See also issue 1558.)

Notes from the October, 2012 meeting:

The consensus of CWG was that this usage should be prohibited, disallowing use of an alias template when a dependent argument can't simply be substituted directly into the type-id.

Additional note, April, 2013:

For another example, consider:

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>({}); 
    } 

There is implementation variance in the handling of this example.

в других случаях, это продолжающийся вопрос без разрешения (AFAIC) в поле зрения.